成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JS學(xué)習(xí)筆記(第6章)(面向?qū)ο笾^承——JS繼承的六大方式)

lscho / 2064人閱讀

摘要:除此之外,在超類型的原型中定義的方法,對(duì)子類型而言也是不可兼得,結(jié)果所有類型都只能用構(gòu)造函數(shù)模式。創(chuàng)建對(duì)象增強(qiáng)對(duì)象指定對(duì)象繼承屬性這個(gè)例子的高效率體現(xiàn)在它只調(diào)用了一次構(gòu)造函數(shù)。

1、原型鏈

原型鏈的基本思想是利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法。
構(gòu)造函數(shù)、原型和實(shí)例的關(guān)系:每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象;原型對(duì)象都包含著一個(gè)指向構(gòu)造函數(shù)的指針;實(shí)例都包含一個(gè)指向原型對(duì)象的內(nèi)部指針。如果我們讓原型對(duì)象等于另一個(gè)類型的實(shí)例,此時(shí)的原型對(duì)象將包含一個(gè)指向另一個(gè)原型的指針,相應(yīng)地另一個(gè)原型中也包含著指向另一個(gè)構(gòu)造函數(shù)的指針……層層遞進(jìn),就構(gòu)成了實(shí)例與原型的鏈條,這就是所謂原型鏈的基本概念。

實(shí)現(xiàn)原型鏈有一種基本模式,其代碼大致如下:

function SuperType() {
    this.property = true;
}
SuperType.prototype.getSuperValue = function() {
    return this.property;
};

function SubType() {
    this.subproperty = false;
}

//繼承了SuperType
SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function() {
    return this.subproperty;
};

var instance = new SubType();
alert(instance.getSuperValue());   //true
(1)不要忘記默認(rèn)的原型

(2)確定原型和實(shí)例的關(guān)系

可以通過兩種方式來確定原型和實(shí)例之間的關(guān)系。
1)使用instanceof操作符,只要用這個(gè)操作符來測試實(shí)例與原型鏈中出現(xiàn)過的構(gòu)造函數(shù),結(jié)果就會(huì)返回true。

alert(instance instanceof Object);  //true
alert(instance instanceof SuperType);  //true
alert(instance instanceof SubType);  //true

2)使用isPrototypeOf()方法。只要是原型鏈中出現(xiàn)過的原型,都可以說是該原型鏈所派生的實(shí)例的原型,因此isPrototypeOf()方法也會(huì)返回true。

alert(Object.prototype.isPrototypeOf(instance));  //true
alert(SuperType.prototype.isPrototypeOf(instance));  //true
alert(SubType.prototype.isPrototypeOf(instance));  //true
(3)謹(jǐn)慎地定義方法

子類型有時(shí)候需要覆蓋超類型中的某個(gè)方法或者需要添加超類型中不存在的某個(gè)方法。但不管這樣,給原型添加方法的代碼一定要放在替換原型的語句之后

function SuperType() {
    this.property = true;
}
SuperType.prototype.getSuperValue = function() {
    return this.property;
};

function SubType() {
    this.subproperty = false;
}

//繼承了SuperType
SubType.prototype = new SuperType();

//添加新方法
SubType.prototype.getSubValue = function() {
    return this.subproperty;
};
//重寫超類型中的方法
SubType.prototype.getSuperValue = function() {
    return false;
};
var instance = new SubType();
alert(instance.getSuperValue());  //false

在通過原型鏈實(shí)現(xiàn)繼承時(shí),不能使用對(duì)象字面量創(chuàng)建原型方法。因?yàn)檫@樣做就會(huì)重寫原型鏈。會(huì)導(dǎo)致實(shí)例與原型鏈之間的聯(lián)系被切斷。

function SubType() {
    this.subproperty = false;
}

//繼承了SuperType
SubType.prototype = new SuperType();

//使用字面量添加新方法,會(huì)導(dǎo)致上一行代碼無效
SubType.prototype = {
    getSubValue : function() {
        return this.subproperty;
    },
    sonOtherMethod : function() {
        return false;
    }
};
var instance = new SubType();
alert(instance.getSuperValue());  //error!
(4)原型鏈的問題

1)最主要的問題來自包含引用類型值的原型,包含引用類型值的原型屬性會(huì)被所有實(shí)例共享;
2)第二個(gè)問題是:在創(chuàng)建子類型的實(shí)例時(shí),不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù);

function SuperType() {
    this.colors = ["red", "blue", "green"];
}

function SubType(){

}
//繼承了SuperType
SubType.prototype = new SuperType();

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);   //"red,blue,green,black"

var instance2 = new SuperType();
alert(instance2.colors);   //"red,blue,green,black"

如上所示,我們對(duì)instance1.colors的修改能夠通過instance2.colors反映出來。

2、借用構(gòu)造函數(shù)

思想:在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù)。
函數(shù)只不過是在特定環(huán)境中執(zhí)行代碼的對(duì)象,因此通過使用apply()和call()方法也可以在新創(chuàng)建的對(duì)象上執(zhí)行構(gòu)造函數(shù)。

function SuperType() {
    this.colors = ["red", "blue", "green"];
}

function SubType(){
    //繼承了SuperType,
    SuperType.call(this);//在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù)
}

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);   //"red,blue,green,black"

var instance2 = new SuperType();
alert(instance2.colors);   //"red,blue,green"

通過使用call()方法或apply()方法,我們實(shí)際上是在新創(chuàng)建的SubType實(shí)例的環(huán)境下調(diào)用了SuperType構(gòu)造函數(shù)。這樣一來,就會(huì)在新SubType對(duì)象上執(zhí)行SuperType()函數(shù)中定義的所有對(duì)象初始化代碼。結(jié)果SubType的每個(gè)實(shí)例就會(huì)具有自己的colors屬性的副本了。

(1)傳遞參數(shù)

相對(duì)于原型鏈而言,借用構(gòu)造函數(shù)的一個(gè)很大優(yōu)勢在于:可以在子類型構(gòu)造函數(shù)中向超類型構(gòu)造函數(shù)傳遞參數(shù)。

function SuperType(name) {
    this.name = name;
}

function SubType() {
    //繼承了SuperType,同時(shí)還傳遞了參數(shù)
    SuperType.call(this, "Nicholas");
    //實(shí)例屬性
    this.age = 29;
}
var instance = new SubType();
alert(instance.name);  //"Nicholas"
alert(intance.age);  //29

為了確保SuperType構(gòu)造函數(shù)不會(huì)重寫子類型的屬性,可以在調(diào)用超類型構(gòu)造函數(shù)后,再添加應(yīng)該在子類型中定義的屬性。

(2)借用構(gòu)造函數(shù)的問題

如果僅僅是借用構(gòu)造函數(shù),那么也就無法避免構(gòu)造函數(shù)模式存在的問題——方法都在構(gòu)造函數(shù)中定義,因此函數(shù)復(fù)用就無從談起。除此之外,在超類型的原型中定義的方法,對(duì)子類型而言也是不可兼得,結(jié)果所有類型都只能用構(gòu)造函數(shù)模式。

3、組合繼承

將原型鏈和借用構(gòu)造函數(shù)的技術(shù)組合到一起。
思想:使用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承,而通過借用構(gòu)造函數(shù)來實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承。
這樣,既通過在原型上定義方法實(shí)現(xiàn)了函數(shù)復(fù)用,又能保證每個(gè)實(shí)例都有它自己的屬性。

function SuperType(name) {
    this.name = name;
    this.color = ["red","blue","green"];
}

SuperType.prototype.sayName = function() {
    alert(this.name);
};
function SubType(name ,age) {
    //繼承屬性
    SuperType.call(this,name);
    this.age = age;
}
//繼承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;  //指向構(gòu)造函數(shù)
SubType.prototype.sayAge = function() {
    alert(this.age);
};
var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors);   //"red,blue,green,black"
instance1.sayName();  //"Nicholas"
instance1.sayAge();  //29

var instance2 = new SubType("Greg" ,27);
alert(instance2.colors);  //"red,blue,green"
instance2.sayName();  //"Greg"
instance2.sayAge();  //27

instanceof()和isPrototypeOf()也能夠用于識(shí)別基于組合繼承創(chuàng)建的對(duì)象、

4、原型式繼承

借助原型可以基于已有的對(duì)象創(chuàng)建新對(duì)象,同時(shí)還不必因此創(chuàng)建自定義類型

function object(o) {
    function F() {}
    F.prototype =o;
    return new F();
}

在object()函數(shù)內(nèi)部,先創(chuàng)建了一個(gè)臨時(shí)性的構(gòu)造函數(shù),然后將傳入的對(duì)象作為這個(gè)構(gòu)造函數(shù)的原型,最后返回這個(gè)臨時(shí)類型的一個(gè)新實(shí)例。

var person = {
    name : "Nicholas",
    friends : ["Shelby", "Court", "Van"]
};
var anotherPerson = object(perosn);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

var yetAbotherPerson = object(perosn);
yetAbotherPerson.name = "Linda";
yetAbotherPerson.firends.push("Barbie");

alert(person.friends);  //"Shelby, Court, Van, Greg, Linda"

ECMAScript5通過新增Object.creat()方法規(guī)范了原型式繼承。這個(gè)方法接收兩個(gè)參數(shù):用作新對(duì)象原型的對(duì)象和為新對(duì)象定義額外屬性的對(duì)象(可選)。在傳入一個(gè)參數(shù)的情況下,Object.create()與object()方法的行為相同。

var person = {
    name : "Nicholas",
    friends : ["Shelby", "Court", "Van"]
};
var anotherPerson = Object.create(perosn);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

var yetAbotherPerson = Object.create(perosn);
yetAbotherPerson.name = "Linda";
yetAbotherPerson.firends.push("Barbie");

alert(person.friends);  //"Shelby, Court, Van, Greg, Linda"


Object.create()方法的第二個(gè)參數(shù)與Object.defineProperties()方法的第二個(gè)參數(shù)格式相同:每個(gè)屬性都通過自己的描述定義的。用這種方式指定的任何屬性都會(huì)覆蓋原型對(duì)象上的同名屬性。

var person = {
    name : "Nicholas",
    friends : ["Shelby", "Court", "Van"]
};
var anotherPerson = Object.create(perosn,{
    name : {
        value : "Grag"
    }
});
 alert(anotherPerson.name);  //"Greg"
5、寄生式繼承

創(chuàng)建一個(gè)僅用于封裝繼承過程的函數(shù),該函數(shù)在內(nèi)部以某種方式來增強(qiáng)對(duì)象,最后再像真的是它做了所有工作一樣返回對(duì)象。以下代碼示范了寄生式繼承模式。

function creatAnother(original) {
     var clone = object(original);   //通過調(diào)用函數(shù)創(chuàng)建一個(gè)新對(duì)象
     clone.sayHi = function() {      //以某種方式來增強(qiáng)這個(gè)對(duì)象
         alert("Hi");
     };
     return clone;  //返回這個(gè)對(duì)象
 }

基于person返回一個(gè)新對(duì)象——anotherPerson。新對(duì)象不僅具有Person的所有屬性和方法,還有自己的sayHi方法。

 function creatAnother(original) {
     var clone = object(original);   //通過調(diào)用函數(shù)創(chuàng)建一個(gè)新對(duì)象
     clone.sayHi = function() {      //以某種方式來增強(qiáng)這個(gè)對(duì)象
         alert("hi");
     };
     return clone;  //返回這個(gè)對(duì)象
 }
 var person = {
    name : "Nicholas",
    friends : ["Shelby", "Court", "Van"]
};

var anotherPerson = creatAnother(person);
anotherPerson.sayHi();  //"hi"
6、寄生組合式繼承

組合繼承最大的問題就是:無論在什么情況下,都會(huì)調(diào)用兩次構(gòu)造函數(shù),一次是在創(chuàng)建子類型原型的時(shí)候,一次是在子類型構(gòu)造函數(shù)的內(nèi)部,導(dǎo)致子類最終會(huì)包含超類對(duì)象的全部實(shí)例屬性,但我們不得不在調(diào)用子類型構(gòu)造函數(shù)時(shí)重寫這些屬性。

function SuperType(name) {
    this.name = name;
    this.color = ["red","blue","green"];
}

SuperType.prototype.sayName = function() {
    alert(this.name);
};
function SubType(name ,age) {
    //繼承屬性
    SuperType.call(this.name);       //第二次調(diào)用SuperType()
    this.age = age;
}
//繼承方法
SubType.prototype = new SuperType();  //第一次調(diào)用SuperType()
SubType.prototype.constructor = SubType;  //指向構(gòu)造函數(shù)
SubType.prototype.sayAge = function() {
    alert(this.age);
};


寄生式組合繼承,就是通過借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈的混成形式來繼承方法。其思想是:不必為了指定子類型的原型而調(diào)用超類型的構(gòu)造函數(shù),我們所需的無非就是超類型原型的一個(gè)副本而已。本質(zhì)上就是,使用寄生式繼承來繼承超類型的原型,然再將結(jié)果指定給子類型的原型。其基本模式如下:

function inheritPrototype(SubType,superType) {
    var prototype = object(superType.prototype);   //創(chuàng)建對(duì)象
    prototype.constructor = subType;               //增強(qiáng)對(duì)象
    subType.prototype = prototype;                 //指定對(duì)象
}

這個(gè)函數(shù)接收兩個(gè)參數(shù):子類型構(gòu)造函數(shù)和超類型構(gòu)造函數(shù)。
第一步是創(chuàng)建超類型原型的一個(gè)副本;
第二步是為創(chuàng)建的副本添加constructor屬性,從而彌補(bǔ)因重寫原型而失去的默認(rèn)的constructor屬性;
第三步將新創(chuàng)建的對(duì)象(即副本)賦值給子類型的原型。

function inheritPrototype(SubType,superType) {
    var prototype = object(superType.prototype);   //創(chuàng)建對(duì)象
    prototype.constructor = subType;               //增強(qiáng)對(duì)象
    subType.prototype = prototype;                 //指定對(duì)象
}

function SuperType(name) {
    this.name = name;
    this.color = ["red","blue","green"];
}

SuperType.prototype.sayName = function() {
    alert(this.name);
};
function SubType(name ,age) {
    //繼承屬性
    SuperType.call(this.name);      
    this.age = age;
}

inheritPrototype(SubType, SuperType);

SubType.prototype.sayAge = function() {
    alert(this.age);
};


這個(gè)例子的高效率體現(xiàn)在它只調(diào)用了一次SuperType構(gòu)造函數(shù)。

7、總結(jié)

JavaScript主要通過原型鏈實(shí)現(xiàn)繼承。原型鏈的構(gòu)建是通過將一個(gè)類型的實(shí)例賦值給另一個(gè)構(gòu)造函數(shù)的原型實(shí)現(xiàn)的。SubType.prototype=new SuperType();這樣,子類型就能夠訪問超類型的所有屬性和方法,這一點(diǎn)與基于類的繼承很相似。原型鏈的問題是對(duì)象實(shí)例共享所有繼承的屬性和方法,因此不適宜多帶帶使用。解決這個(gè)問題的技術(shù)是借用構(gòu)造函數(shù),即在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù)SuperType.call(this,name); 這樣就可以做到每個(gè)實(shí)例都具有自己的屬性,同時(shí)還能保證只使用構(gòu)造函數(shù)模式來定義類型。使用最多的繼承模式是組合繼承,這種模式使用原型鏈繼承共享的屬性和方法,而借用構(gòu)造函數(shù)繼承實(shí)例屬性。

此外,還存在下列可供選擇的繼承模式:

原型式繼承,可以在不必預(yù)先定義構(gòu)造函數(shù)的情況下實(shí)現(xiàn)繼承,其本質(zhì)是執(zhí)行給定對(duì)象的淺復(fù)制。而復(fù)制的副本還可以得到進(jìn)一步的改造。

寄生式繼承,與原型式繼承非常相似,也是基于某個(gè)對(duì)象或某些信息創(chuàng)建一個(gè)對(duì)象,然后增強(qiáng)對(duì)象,最后返回對(duì)象。為了解決組合繼承模式由于多次調(diào)用超類型函數(shù)而導(dǎo)致的低效率問題,可以將這個(gè)模式與組合繼承一起使用。

寄生組合式繼承,集寄生式繼承與組合繼承的優(yōu)點(diǎn)于一身,是實(shí)現(xiàn)基于類型繼承的最有效的方式

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/109052.html

相關(guān)文章

  • JS學(xué)習(xí)筆記6)(實(shí)現(xiàn)繼承幾種方式

    摘要:使用最多的繼承模式是組合繼承,這種模式使用原型鏈繼承共享的屬性和方法,而借用構(gòu)造函數(shù)繼承實(shí)例屬性。原型式繼承,可以在不必預(yù)先定義構(gòu)造函數(shù)的情況下實(shí)現(xiàn)繼承,其本質(zhì)是執(zhí)行給定對(duì)象的淺復(fù)制。 1、原型鏈實(shí)現(xiàn)繼承 function SuperType() { this.property = true; } SuperType.prototype.getSuperValue = func...

    hiyayiji 評(píng)論0 收藏0
  • 讀《javaScript高級(jí)程序設(shè)計(jì)-6繼承

    摘要:此時(shí)的原型對(duì)象包括一個(gè)指向另一個(gè)原型的指針,相應(yīng)的,另一個(gè)原型中的指向另一個(gè)構(gòu)造函數(shù)。這種關(guān)系層層遞進(jìn),就通過一個(gè)原型對(duì)象鏈接另一個(gè)構(gòu)造函數(shù)的原型對(duì)象的方式實(shí)現(xiàn)了繼承。 讀這篇之前,最好是已讀過我前面的關(guān)于對(duì)象的理解和封裝類的筆記。第6章我一共寫了3篇總結(jié),下面是相關(guān)鏈接:讀《javaScript高級(jí)程序設(shè)計(jì)-第6章》之理解對(duì)象讀《javaScript高級(jí)程序設(shè)計(jì)-第6章》之封裝類 一...

    villainhr 評(píng)論0 收藏0
  • 紅寶書筆記-6-面向對(duì)象程序設(shè)計(jì)

    摘要:構(gòu)造函數(shù)本身也是函數(shù),只不過可以用來創(chuàng)建對(duì)象而已。在創(chuàng)建子類型的實(shí)例時(shí),沒有辦法在不影響所有對(duì)象實(shí)例的情況下,不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù)。借用構(gòu)造函數(shù)又叫偽造對(duì)象或經(jīng)典繼承。 本章內(nèi)容 理解對(duì)象屬性 理解并創(chuàng)建對(duì)象 理解繼承 ECMA-262 把對(duì)象定義為:無序?qū)傩缘募?,其屬性可以包含基本值、?duì)象或者函數(shù)。嚴(yán)格來講,這就相當(dāng)于說對(duì)象是一組沒有特定順序的值。 每個(gè)對(duì)象都是基于...

    hizengzeng 評(píng)論0 收藏0
  • JS學(xué)習(xí)筆記6)(面向對(duì)象程序設(shè)計(jì)理解對(duì)象

    摘要:其中,描述符對(duì)象的屬性必須是和。吧設(shè)置為,表示不能從對(duì)象中刪除屬性。這個(gè)方法接收兩個(gè)對(duì)象參數(shù)要添加和修改其屬性值的對(duì)象,第二個(gè)是與第一個(gè)對(duì)象中要添加和修改的屬性值一一對(duì)應(yīng)。 理解對(duì)象 1、創(chuàng)建自定義對(duì)象的兩種方法: (1)創(chuàng)建一個(gè)Object實(shí)例,然后再為它添加屬性和方法。 var person = new Object(); person.name = Nicholas; ...

    FingerLiu 評(píng)論0 收藏0
  • 接口

    摘要:前言這一系列的文章將主要基于設(shè)計(jì)模式這本書的要點(diǎn)還有一些翻閱的博客文章借鑒來源會(huì)注明外加自己的一些與直覺不同于其他設(shè)計(jì)模式類的書設(shè)計(jì)模式是一本講述設(shè)計(jì)模式在動(dòng)態(tài)語言中的實(shí)現(xiàn)的書它從設(shè)計(jì)的角度教人編寫代碼書中的許多實(shí)例代碼來自實(shí)戰(zhàn)項(xiàng)目對(duì)面向?qū)? 前言 這一系列的文章將主要基于js設(shè)計(jì)模式這本書的要點(diǎn)還有一些翻閱的博客文章,借鑒來源會(huì)注明,外加自己的一些demo與直覺.不同于其他設(shè)計(jì)模式類的...

    zhjx922 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<