国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JS學習筆記(第6章)(面向對象之繼承——JS繼承的六大方式)

lscho / 2056人閱讀

摘要:除此之外,在超類型的原型中定義的方法,對子類型而言也是不可兼得,結果所有類型都只能用構造函數模式。創建對象增強對象指定對象繼承屬性這個例子的高效率體現在它只調用了一次構造函數。

1、原型鏈

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

實現原型鏈有一種基本模式,其代碼大致如下:

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)不要忘記默認的原型

(2)確定原型和實例的關系

可以通過兩種方式來確定原型和實例之間的關系。
1)使用instanceof操作符,只要用這個操作符來測試實例與原型鏈中出現過的構造函數,結果就會返回true。

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

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

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

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

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

在通過原型鏈實現繼承時,不能使用對象字面量創建原型方法。因為這樣做就會重寫原型鏈。會導致實例與原型鏈之間的聯系被切斷。

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

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

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

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

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"

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

2、借用構造函數

思想:在子類型構造函數的內部調用超類型構造函數。
函數只不過是在特定環境中執行代碼的對象,因此通過使用apply()和call()方法也可以在新創建的對象上執行構造函數。

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

function SubType(){
    //繼承了SuperType,
    SuperType.call(this);//在子類型構造函數的內部調用超類型構造函數
}

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()方法,我們實際上是在新創建的SubType實例的環境下調用了SuperType構造函數。這樣一來,就會在新SubType對象上執行SuperType()函數中定義的所有對象初始化代碼。結果SubType的每個實例就會具有自己的colors屬性的副本了。

(1)傳遞參數

相對于原型鏈而言,借用構造函數的一個很大優勢在于:可以在子類型構造函數中向超類型構造函數傳遞參數。

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

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

為了確保SuperType構造函數不會重寫子類型的屬性,可以在調用超類型構造函數后,再添加應該在子類型中定義的屬性。

(2)借用構造函數的問題

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

3、組合繼承

將原型鏈和借用構造函數的技術組合到一起。
思想:使用原型鏈實現對原型屬性和方法的繼承,而通過借用構造函數來實現對實例屬性的繼承。
這樣,既通過在原型上定義方法實現了函數復用,又能保證每個實例都有它自己的屬性。

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;  //指向構造函數
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()也能夠用于識別基于組合繼承創建的對象、

4、原型式繼承

借助原型可以基于已有的對象創建新對象,同時還不必因此創建自定義類型

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

在object()函數內部,先創建了一個臨時性的構造函數,然后將傳入的對象作為這個構造函數的原型,最后返回這個臨時類型的一個新實例。

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()方法規范了原型式繼承。這個方法接收兩個參數:用作新對象原型的對象和為新對象定義額外屬性的對象(可選)。在傳入一個參數的情況下,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()方法的第二個參數與Object.defineProperties()方法的第二個參數格式相同:每個屬性都通過自己的描述定義的。用這種方式指定的任何屬性都會覆蓋原型對象上的同名屬性。

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

創建一個僅用于封裝繼承過程的函數,該函數在內部以某種方式來增強對象,最后再像真的是它做了所有工作一樣返回對象。以下代碼示范了寄生式繼承模式。

function creatAnother(original) {
     var clone = object(original);   //通過調用函數創建一個新對象
     clone.sayHi = function() {      //以某種方式來增強這個對象
         alert("Hi");
     };
     return clone;  //返回這個對象
 }

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

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

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

組合繼承最大的問題就是:無論在什么情況下,都會調用兩次構造函數,一次是在創建子類型原型的時候,一次是在子類型構造函數的內部,導致子類最終會包含超類對象的全部實例屬性,但我們不得不在調用子類型構造函數時重寫這些屬性。

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);       //第二次調用SuperType()
    this.age = age;
}
//繼承方法
SubType.prototype = new SuperType();  //第一次調用SuperType()
SubType.prototype.constructor = SubType;  //指向構造函數
SubType.prototype.sayAge = function() {
    alert(this.age);
};


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

function inheritPrototype(SubType,superType) {
    var prototype = object(superType.prototype);   //創建對象
    prototype.constructor = subType;               //增強對象
    subType.prototype = prototype;                 //指定對象
}

這個函數接收兩個參數:子類型構造函數和超類型構造函數。
第一步是創建超類型原型的一個副本;
第二步是為創建的副本添加constructor屬性,從而彌補因重寫原型而失去的默認的constructor屬性;
第三步將新創建的對象(即副本)賦值給子類型的原型。

function inheritPrototype(SubType,superType) {
    var prototype = object(superType.prototype);   //創建對象
    prototype.constructor = subType;               //增強對象
    subType.prototype = prototype;                 //指定對象
}

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);
};


這個例子的高效率體現在它只調用了一次SuperType構造函數。

7、總結

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

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

原型式繼承,可以在不必預先定義構造函數的情況下實現繼承,其本質是執行給定對象的淺復制。而復制的副本還可以得到進一步的改造。

寄生式繼承,與原型式繼承非常相似,也是基于某個對象或某些信息創建一個對象,然后增強對象,最后返回對象。為了解決組合繼承模式由于多次調用超類型函數而導致的低效率問題,可以將這個模式與組合繼承一起使用。

寄生組合式繼承,集寄生式繼承與組合繼承的優點于一身,是實現基于類型繼承的最有效的方式

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/109052.html

相關文章

  • JS學習筆記6)(實現繼承幾種方式

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

    hiyayiji 評論0 收藏0
  • 讀《javaScript高級程序設計-6繼承

    摘要:此時的原型對象包括一個指向另一個原型的指針,相應的,另一個原型中的指向另一個構造函數。這種關系層層遞進,就通過一個原型對象鏈接另一個構造函數的原型對象的方式實現了繼承。 讀這篇之前,最好是已讀過我前面的關于對象的理解和封裝類的筆記。第6章我一共寫了3篇總結,下面是相關鏈接:讀《javaScript高級程序設計-第6章》之理解對象讀《javaScript高級程序設計-第6章》之封裝類 一...

    villainhr 評論0 收藏0
  • 紅寶書筆記-6-面向對象程序設計

    摘要:構造函數本身也是函數,只不過可以用來創建對象而已。在創建子類型的實例時,沒有辦法在不影響所有對象實例的情況下,不能向超類型的構造函數中傳遞參數。借用構造函數又叫偽造對象或經典繼承。 本章內容 理解對象屬性 理解并創建對象 理解繼承 ECMA-262 把對象定義為:無序屬性的集合,其屬性可以包含基本值、對象或者函數。嚴格來講,這就相當于說對象是一組沒有特定順序的值。 每個對象都是基于...

    hizengzeng 評論0 收藏0
  • JS學習筆記6)(面向對象程序設計理解對象

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

    FingerLiu 評論0 收藏0
  • 接口

    摘要:前言這一系列的文章將主要基于設計模式這本書的要點還有一些翻閱的博客文章借鑒來源會注明外加自己的一些與直覺不同于其他設計模式類的書設計模式是一本講述設計模式在動態語言中的實現的書它從設計的角度教人編寫代碼書中的許多實例代碼來自實戰項目對面向對 前言 這一系列的文章將主要基于js設計模式這本書的要點還有一些翻閱的博客文章,借鑒來源會注明,外加自己的一些demo與直覺.不同于其他設計模式類的...

    zhjx922 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<