偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Javascript面向?qū)ο蠡A(chǔ)以及接口和繼承類的實(shí)現(xiàn)

開發(fā) 前端
本文主要講述一些Javascript面向?qū)ο蟮幕A(chǔ)以及接口和繼承類的實(shí)現(xiàn)。作者結(jié)合Javascript來設(shè)計(jì)前臺(tái)方面的“設(shè)計(jì)模式”,以對(duì)后臺(tái)“設(shè)計(jì)模式”做個(gè)補(bǔ)充。

在開始設(shè)計(jì)模式的書寫之前,有必要對(duì)Javascript面向?qū)ο蟮母拍钕茸鰝€(gè)介紹,那么這篇文章就以面向?qū)ο蠡A(chǔ)作為起點(diǎn)吧。

理論知識(shí)

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

2. 面向?qū)ο蟾拍畈槐囟嗾f,封裝,繼承,多態(tài);

3. Javascript對(duì)象的類型主要分為三種:本地對(duì)象,如String,Array,Date等;內(nèi)置對(duì)象,如Global,Math等;宿主對(duì)象,是指傳統(tǒng)面向?qū)ο蟪绦蛟O(shè)計(jì)中的作用域,如公有,保護(hù),私有,靜態(tài)等等。

主要內(nèi)容

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

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

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

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

function Man() {
    // 私有靜態(tài)屬性
    var Sex = "男";
    //私有靜態(tài)方法
    function checkSex() {
        return (Sex == "男");
    }
    //私有方法
    this._getSex = function() {
        //調(diào)用私有靜態(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() {
    //調(diào)用私有方法
    return this._getSex();
};
//公共靜態(tài)方法
Man.say = function() {
    return "Happy new year!";
}

這樣的類是否看起來和傳統(tǒng)的類很相似了呢?

2.接下來這個(gè)是本篇的一個(gè)重點(diǎn),就是用Javascript如何設(shè)計(jì)一個(gè)接口,然后讓類繼承于它。

首先,先讓我們看傳統(tǒng)的C#語言是如何設(shè)計(jì)接口的吧:

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),(但不能聲明變量),但是并不能設(shè)置這些成員的具體值,也就是說,只能定義,不能給它里面定義的東西賦值,而接口作為它的繼承類或者派生類的規(guī)約,繼承類或者它的派生類能夠共同完成接口屬性、方法、事件和類型的具體實(shí)現(xiàn),因?yàn)檫@里GetName(),SetName(),不管是方法名還是屬性調(diào)用順序上都是要保持一致的;

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

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

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

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

看到Man的構(gòu)造函數(shù)里面包含

Interface.registerImplements(this, Person);

它是用來將實(shí)例化的this對(duì)象繼承于Person接口,然后繼承類對(duì)接口的方法進(jìn)行實(shí)現(xiàn)。

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

先看Interface的構(gòu)造函數(shù)部分

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

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

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

#p#

調(diào)用方法部分:

Interface.registerImplements = function(object) { 

    if(arguments.length < 2) {
        throw new Error("接口的實(shí)現(xiàn)必須包含至少2個(gè)參數(shù).");
    } 

    for(var i = 1, len = arguments.length; i < len; i++) {
        var interface = arguments[i];
        if(interface.constructor !== Interface) {
            throw new Error("從第2個(gè)以上的參數(shù)必須為接口實(shí)例.");
        }
        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("接口的實(shí)現(xiàn)對(duì)象不能執(zhí)行" + interface.name + "的接口方法" + method + ",因?yàn)樗也坏交蛘卟黄ヅ?");
            }
        }
    }
}; 

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

Function.prototype.getParameters = function() { 

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

getParrameters()方法作為Function對(duì)象的一個(gè)擴(kuò)展,功能是取得方法含有的參數(shù)數(shù)組;

Interface.js完整的代碼如下:

Interface.js文件

function Interface(name, methods) 
{
    if(arguments.length != 2) {
        throw new Error("接口構(gòu)造函數(shù)含" + arguments.length + "個(gè)參數(shù), 但需要2個(gè)參數(shù).");
    }
    this.name = name;
    this.methods = [];
    if(methods.length < 1) {
        throw new Error("第二個(gè)參數(shù)為空數(shù)組.");
    }
    for(var i = 0, len = methods.length; i < len; i++) {
        if(typeof methods[i][0] !== 'string') {
            throw new Error("接口構(gòu)造函數(shù)第一個(gè)參數(shù)必須為字符串類型.");
        }
        if(methods[i][1] && typeof methods[i][1] !== 'number') {
            throw new Error("接口構(gòu)造函數(shù)第二個(gè)參數(shù)必須為整數(shù)類型.");
        }
        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("接口的實(shí)現(xiàn)必須包含至少2個(gè)參數(shù).");
    } 

    for(var i = 1, len = arguments.length; i < len; i++) {
        var interface = arguments[i];
        if(interface.constructor !== Interface) {
            throw new Error("從第2個(gè)以上的參數(shù)必須為接口實(shí)例.");
        }
        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("接口的實(shí)現(xiàn)對(duì)象不能執(zhí)行" + interface.name + "的接口方法" + method + ",因?yàn)樗也坏交蛘卟黄ヅ?");
            }
        }
    }
}; 

Function.prototype.getParameters = function() { 

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

好了該創(chuàng)建一個(gè)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();" />

最終結(jié)果為:"Leepy"的彈出框。

這里還有一點(diǎn)要強(qiáng)調(diào),如果接口上的方法沒有在繼承類上得到完全實(shí)現(xiàn),或者方法參數(shù)個(gè)數(shù)不匹配,那么就會(huì)提示錯(cuò)誤。

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

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);實(shí)際上是將Man中的關(guān)鍵字this賦值于SchoolBoy對(duì)象中去,那么SchoolBoy就擁有了Man構(gòu)造函數(shù)中的name屬性了。

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

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

然后看看效果:

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

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

【編輯推薦】

  1. JavaScript將成Silverlight的最大對(duì)手?
  2. 探秘IE8 JavaScript功能超乎想象
  3. JavaScript+CSS實(shí)現(xiàn)網(wǎng)頁換膚功能
責(zé)任編輯:楊鵬飛 來源: 博客園
相關(guān)推薦

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 11:17:18

javascript

2011-05-13 09:58:46

javascript

2011-05-13 10:51:25

javascript

2011-05-13 11:27:59

javascript

2011-05-13 12:38:58

javascript

2011-05-13 11:05:52

javascript

2018-12-14 11:30:00

JavaScript編程前端

2020-10-20 08:35:34

JS基礎(chǔ)進(jìn)階

2009-07-08 17:42:26

this屬性

2016-10-11 15:42:08

2021-01-28 08:34:30

Java對(duì)象定義

2009-07-08 17:48:18

prototype屬性

2009-07-08 17:51:45

constructor

2020-12-24 08:36:14

JavaJava基礎(chǔ)

2011-07-08 10:25:55

JavaScript

2009-07-02 13:25:00

消除實(shí)現(xiàn)繼承面向接口編程Java
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)