自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Javascript面向對象基礎以及接口和繼承類的實現

開發(fā) 前端
本文主要講述一些Javascript面向對象的基礎以及接口和繼承類的實現。作者結合Javascript來設計前臺方面的“設計模式”,以對后臺“設計模式”做個補充。

在開始設計模式的書寫之前,有必要對Javascript面向對象的概念先做個介紹,那么這篇文章就以面向對象基礎作為起點吧。

理論知識

1. 首先Javascript是弱類型語言,它定義變量時不必聲明類型,如var Person = new Person(),它的變量類型為“var”,現在的C# 3.0也引進了這種匿名類型的概念,弱類型的變量產生了極大的靈活性,因為Javascript會根據需要來進行類型轉換。所以這也決定了它采用了晚綁定的方法,即在運行后才知道變量的類型;

2. 面向對象概念不必多說,封裝,繼承,多態(tài);

3. Javascript對象的類型主要分為三種:本地對象,如String,Array,Date等;內置對象,如Global,Math等;宿主對象,是指傳統面向對象程序設計中的作用域,如公有,保護,私有,靜態(tài)等等。

主要內容

1. 現在讓我們來看看Javascript怎樣創(chuàng)建對象的:

function Man() {
   //  
}
Man.prototype.getNickName = function() {
    return "Leepy";
}; 

var man = new Man();
var name = man.getNickName(); 

這樣就創(chuàng)建了最簡單的類和對象,其中我們可以把function Man() {} 看作是Man類的構造函數,getNickName()看作是Man類的方法,準確說可以“當作”是Man類的公共方法;為什么要說是當作呢?那是因為其實Javascript實際上并沒有一個私有共有的劃分,因此開發(fā)者們自己指定了這樣的規(guī)約,那么規(guī)約是什么樣的呢?我這里把Man類的清單完整地列出來:

function Man() {
    // 私有靜態(tài)屬性
    var Sex = "男";
    //私有靜態(tài)方法
    function checkSex() {
        return (Sex == "男");
    }
    //私有方法
    this._getSex = function() {
        //調用私有靜態(tài)方法
        if(checkSex())
            return "男";
        else
            return "女";
    }
    //私有方法
    this.getFirstName = function() { 
        return "Li";
    };
    //私有方法
    this.getLastName = function() {
        return "Ping";
    };
}
//公共方法
Man.prototype.getNickName = function() {
    return "Leepy";
};
//公共方法
Man.prototype.getFullName = function() {
    return this.getFirstName() + " " + this.getLastName();
};
//公共方法
Man.prototype.getSex = function() {
    //調用私有方法
    return this._getSex();
};
//公共靜態(tài)方法
Man.say = function() {
    return "Happy new year!";
}

這樣的類是否看起來和傳統的類很相似了呢?

2.接下來這個是本篇的一個重點,就是用Javascript如何設計一個接口,然后讓類繼承于它。

首先,先讓我們看傳統的C#語言是如何設計接口的吧:

public interface Person
{
    string GetName();
    void SetName(string name);
}
public class Man : Person
{
    private string _name; 

    public string GetName()
    {
        return _name;
    }
    public void SetName(string name)
    {
        _name = name;
    }
} 

接口中可以聲明屬性、方法、事件和類型(Structure),(但不能聲明變量),但是并不能設置這些成員的具體值,也就是說,只能定義,不能給它里面定義的東西賦值,而接口作為它的繼承類或者派生類的規(guī)約,繼承類或者它的派生類能夠共同完成接口屬性、方法、事件和類型的具體實現,因為這里GetName(),SetName(),不管是方法名還是屬性調用順序上都是要保持一致的;

那么有了這樣的一個基于接口的思想,我們設計Javascript的接口類的時候也需要考慮到這個規(guī)范。我先從主JS文件調用端開始說起:

var Person = new Interface("Person", [["getName", 0], ["setName", 1]]); 

其中Interface類是稍后要說的接口類,第一個參數"Person"是接口類的名稱,第二個參數是個二維數組,"getName"是接口方法的名稱,"0"是該方法所帶的參數個數(因為Javascript是弱語言,所以類型是不確定的,所以只要記住參數個數就好,"0"可以省略不寫),"setName"同理。這樣一個接口定義好了。怎樣使用它呢?

function Man() 
{
    this.name = "";
    Interface.registerImplements(this, Person);
}
Man.prototype.getName = function() {
    return this.name;
};
Man.prototype.setName = function(name) {
    this.name = name;
}; 

看到Man的構造函數里面包含

Interface.registerImplements(this, Person);

它是用來將實例化的this對象繼承于Person接口,然后繼承類對接口的方法進行實現。

代碼看起來是不是很清晰和簡單呢,那么現在要開始介紹真正的核心代碼Interface.js了:

先看Interface的構造函數部分

unction Interface(name, methods) 
{
    if(arguments.length != 2) {
        throw new Error("接口構造函數含" + arguments.length + "個參數, 但需要2個參數.");
    }
    this.name = name;
    this.methods = [];
    if(methods.length < 1) {
        throw new Error("第二個參數為空數組.");
    }
    for(var i = 0, len = methods.length; i < len; i++) {
        if(typeof methods[i][0] !== 'string') {
            throw new Error("接口構造函數第一個參數必須為字符串類型.");
        }
        if(methods[i][1] && typeof methods[i][1] !== 'number') {
            throw new Error("接口構造函數第二個參數必須為整數類型.");
        }
        if(methods[i].length == 1) {
            methods[i][1] = 0;
        } 

        this.methods.push(methods[i]);
    }    
};

剛才看到了var Person = new Interface("Person", [["getName", 0], ["setName", 1]]);,這里將兩個參數分別保存起來;

#p#

調用方法部分:

Interface.registerImplements = function(object) { 

    if(arguments.length < 2) {
        throw new Error("接口的實現必須包含至少2個參數.");
    } 

    for(var i = 1, len = arguments.length; i < len; i++) {
        var interface = arguments[i];
        if(interface.constructor !== Interface) {
            throw new Error("從第2個以上的參數必須為接口實例.");
        }
        for(var j = 0, methodsLen = interface.methods.length; j < methodsLen; j++) {
            var method = interface.methods[j][0];
            if(!object[method] || typeof object[method] !== 'function' || object[method].getParameters().length != interface.methods[j][1]) {
                throw new Error("接口的實現對象不能執(zhí)行" + interface.name + "的接口方法" + method + ",因為它找不到或者不匹配.");
            }
        }
    }
}; 

剛才這句Interface.registerImplements(this, Person);,實際上這里是把this對象的方法名以及參數個數與剛Person保存的methods逐一進行比較,如果找不到或者不匹配,就警告錯誤;其中object[method].getParameters().length,調用了如下的代碼:

Function.prototype.getParameters = function() { 

    var str = this.toString();
    var paramString = str.slice(str.indexOf('(') + 1, str.indexOf(')')).rep
lace(/\s*/g,''); //取得參數字符串 try { return (paramString.length == 0 ? [] : paramString.split(',')); } catch(err) { throw new Error("函數不合法!"); } }

getParrameters()方法作為Function對象的一個擴展,功能是取得方法含有的參數數組;

Interface.js完整的代碼如下:

Interface.js文件

function Interface(name, methods) 
{
    if(arguments.length != 2) {
        throw new Error("接口構造函數含" + arguments.length + "個參數, 但需要2個參數.");
    }
    this.name = name;
    this.methods = [];
    if(methods.length < 1) {
        throw new Error("第二個參數為空數組.");
    }
    for(var i = 0, len = methods.length; i < len; i++) {
        if(typeof methods[i][0] !== 'string') {
            throw new Error("接口構造函數第一個參數必須為字符串類型.");
        }
        if(methods[i][1] && typeof methods[i][1] !== 'number') {
            throw new Error("接口構造函數第二個參數必須為整數類型.");
        }
        if(methods[i].length == 1) {
            methods[i][1] = 0;
        } 

        this.methods.push(methods[i]);
    }    
}; 

Interface.registerImplements = function(object) { 

    if(arguments.length < 2) {
        throw new Error("接口的實現必須包含至少2個參數.");
    } 

    for(var i = 1, len = arguments.length; i < len; i++) {
        var interface = arguments[i];
        if(interface.constructor !== Interface) {
            throw new Error("從第2個以上的參數必須為接口實例.");
        }
        for(var j = 0, methodsLen = interface.methods.length; j < methodsLen; j++) {
            var method = interface.methods[j][0];
            if(!object[method] || typeof object[method] !== 'function' || object[method].getParameters().length != interface.methods[j][1]) {
                throw new Error("接口的實現對象不能執(zhí)行" + interface.name + "的接口方法" + method + ",因為它找不到或者不匹配.");
            }
        }
    }
}; 

Function.prototype.getParameters = function() { 

    var str = this.toString();
    var paramString = str.slice(str.indexOf('(') + 1, str.indexOf(')')).replace(/\s*/g,'');     //取得參數字符串
    try
    {
        return (paramString.length == 0 ? [] : paramString.split(','));
    }
    catch(err)
    {
        throw new Error("函數不合法!");
    }
} 

好了該創(chuàng)建一個html頁面來試試效果了:

<script type="text/javascript">
function test()
{
    var man = new Man();
    man.setName("Leepy");
    alert(man.getName());
}
</script> 

<input type="button" value="click" onclick="test();" />

最終結果為:"Leepy"的彈出框。

這里還有一點要強調,如果接口上的方法沒有在繼承類上得到完全實現,或者方法參數個數不匹配,那么就會提示錯誤。

3. 如果我要一個類繼承于另一個類該怎么做呢,繼續(xù)看例子,這里我再定義一個SchoolBoy(男學生)類:

function SchoolBoy(classNo, post)
{
    Man.call(this);
    this._chassNo = classNo;
    this._post = post;
}
SchoolBoy.prototype = new Man();
SchoolBoy.prototype.getName = function() {
    return "Mr " + this.name;
}
SchoolBoy.prototype.setName = function(name) {
    this.name = name + "'s";
}

其中Man.call(this);實際上是將Man中的關鍵字this賦值于SchoolBoy對象中去,那么SchoolBoy就擁有了Man構造函數中的name屬性了。

SchoolBoy.prototype = new Man();實際上是把Man的prototype賦值給SchoolBoy.prototype,那么SchoolBoy就有了Man類中的方法。

而后面跟著的getName(),setName(),實際上是覆蓋了前面繼承于Man類中的方法了。

然后看看效果:

var schoolboy = new SchoolBoy("三年二班", "班長");
schoolboy.setName("周杰倫");
alert(schoolboy.getName());

最后結果為:"Mr 周杰倫's"的彈出框。

【編輯推薦】

  1. JavaScript將成Silverlight的最大對手?
  2. 探秘IE8 JavaScript功能超乎想象
  3. JavaScript+CSS實現網頁換膚功能
責任編輯:楊鵬飛 來源: 博客園
相關推薦

2023-09-27 23:28:28

Python編程

2011-05-25 10:59:26

Javascript繼承

2011-05-25 11:15:02

Javascript繼承

2010-10-08 09:13:15

oop模式JavaScript

2011-05-13 12:38:58

javascript

2011-05-13 09:58:46

javascript

2011-05-13 10:51:25

javascript

2011-05-13 11:17:18

javascript

2011-05-13 11:27:59

javascript

2018-12-14 11:30:00

JavaScript編程前端

2011-05-13 11:05:52

javascript

2020-10-20 08:35:34

JS基礎進階

2009-07-08 17:42:26

this屬性

2016-10-11 15:42:08

2021-01-28 08:34:30

Java對象定義

2009-07-08 17:51:45

constructor

2009-07-08 17:48:18

prototype屬性

2011-07-08 10:25:55

JavaScript

2020-12-24 08:36:14

JavaJava基礎

2009-07-02 13:25:00

消除實現繼承面向接口編程Java
點贊
收藏

51CTO技術棧公眾號