摘要:繼承原型鏈原型鏈是實現(xiàn)繼承的主要方法。臨時的構(gòu)造函數(shù)將傳入的對象作為這個構(gòu)造函數(shù)的原型返回新實例以為原型創(chuàng)建一個新實例不僅屬于所有,而且也會被共享。上訴例子只調(diào)用了一次構(gòu)造函數(shù),因此避免了在上面創(chuàng)建不必要的多余的屬性。
繼承 1 原型鏈
原型鏈是實現(xiàn)繼承的主要方法。其基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。
構(gòu)造函數(shù)、原型和實例的關(guān)系
每個構(gòu)造函數(shù)都有一個原型對象,原型對象都包含一個指向構(gòu)造函數(shù)的指針,而實例都包含一個指向原型對象的內(nèi)部指針。
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; } function SubType(){ this.subproperty = false; } // 使SubType繼承SuperType的實例 本質(zhì)是重寫原型對象 SubType.prototype = new SuperType(); SubType.prototype.getValue = function(){ return this.subproperty; } var instance = new SubType(); alert(instance.getSuperValue());//true
注意 :==instance.constructor現(xiàn)在指向的是SuperType,這是因為原來SubType的原型指向了另一個對象--SuperType的原型,而這個原型對象的constructor屬性指向的是SuperType==
默認的原型 Objec
確定原型與實例的關(guān)系
instanceof:用這個操作符來測試實例與原型鏈中出現(xiàn)過的構(gòu)造函數(shù),結(jié)果就會返回true
alert(instance instanceof Object); //true alert(instance instanceof SuperType); //true alert(instance instanceof SubType); //true
使用isPrototypeOf()方法,只要是原型鏈中出現(xiàn)的原型,都可以說是該原型鏈所派生的實例的原型
alert(Object.prototype isPrototypeOf(instance)); //true alert(SuperType.prototype isPrototypeOf(instance)); alert(SubType.prototype isPrototypeOf(instance));
通過原型鏈實現(xiàn)繼承時,不能使用對象字面量創(chuàng)建原型方法,因為這樣會重寫原型鏈
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; } function SubType(){ this.subproperty = false; } SubType.prototype = new SuperType(); // 使用對象字面量創(chuàng)建原型方法,會重寫原型鏈 SubType.prototype = { getSubValue: function(){ return this.subproperty; } }; var instance = new SubType(); alert(instance.getSuperValue());//error!!
原型鏈的問題
包含引用類型值的原型屬性會被所有實例共享,因此在構(gòu)造函數(shù)中定義屬性而不是在原型對象中定義屬性。
在通過原型來實現(xiàn)繼承時,原型實際上會變成另一個類型的實例。于是,原先的實例屬性也就變成了現(xiàn)在的原型屬性了。
function SuperType(){ this.color = ["red", "blue", "green"]; this.name = "Nicholas"; } function SubType(){ } SubType.prototype = new SuperType(); var instance1 = new SubType(); instance1.colors.push("black"); alert(instance1.colors); //"red","blue","green","black" instance1.name = "Tom"; alert(instance1.name); //"Tom" var instance2 = new SubType(); // colors是引用類型,會被所有實例共享 alert(instance2.colors); // "red","blue","green","black" alert(instance2.name); //"Nicholas"
沒有辦法在不影響所有對象實例的情況下,給超類型的構(gòu)造函數(shù)傳遞參數(shù)
function SuperType(name){ this.name = name; } function SubType(name){ } // ??如何向超類型的構(gòu)造函數(shù)傳遞參數(shù)?? SubType.prototype = new SuperType(); var instance2 = new SubType(name);
綜合以上情況,實踐中很少會多帶帶使用原型鏈
2.借用構(gòu)造函數(shù)在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù)。
function SuperType(){ this.colors=["red","blue","green"]; } function SubType(){ // superType.call(this); } var instance1 = new SubType(); instance1.colors.push("black"); alert(instance1.colors); // "red,blue,green,black" bar instance2 = new SubType(); alert(instance2.colors); //"red,blue,green"
使用這種方式,可以在子類型構(gòu)造函數(shù)中向超類型構(gòu)造函數(shù)傳遞參數(shù)。
function SuperType(name){ this.name=name; } function SubType(){ Super.call(this,"Nicholas"); this.age = 29; } var instance = new SubType(); alert(instance.name);//"Nicholas"
相關(guān)問題:
會出現(xiàn)與構(gòu)造函數(shù)模式相同的問題——方法都在構(gòu)造函數(shù)中定義,函數(shù)復(fù)用就無從談起了。而且在超類型的原型中定義的方法,對于子類型也是不可見的。
3.組合繼承——JavaScrip最常用的繼承模式使用原型鏈實現(xiàn)對原型屬性和方法的繼承(通過在原型上定義方法實現(xiàn)了函數(shù)復(fù)用),通過借用構(gòu)造函數(shù)來實現(xiàn)對實例屬性的繼承(保證每個實例都有自己的屬性,而且可以向超類的構(gòu)造函數(shù)傳遞參數(shù))。
function SuperType(name){ this.name=name; this.colors=["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.sayAge = function(){ alert(this.age); }; var instance1 = new SubType("Nicholas",29); instance1.sayName(); //"Nicholas" instance1.sayAge(); //29 var instance2 = new SubType("Greg",27); instance2.sayName(); //"Greg" instance2.sayAge(); //274 原型式繼承
借助原型可以基于已有的對象創(chuàng)建新對象,同時還不必因此創(chuàng)建自定義類型。
function object(o){ // 臨時的構(gòu)造函數(shù) function F(){} // 將傳入的對象作為這個構(gòu)造函數(shù)的原型 F.prototype = o; // 返回新實例 return new F(); } var person = { name:"Nicholas", friends:["shelby","court","van"] }; // 以person為原型創(chuàng)建一個新實例 var anotherPerson = object(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = object(person); yetAnotherPerson.name = "linda"; yetAnotherPerson.friends.push("barbie"); alert(person.friends); //"shelby,court,van,rob,barbie"
person.friends不僅屬于person所有,而且也會被anotherPerson、yetAnotherPerson共享。
ECMAScript5通過Object.create()方法規(guī)范化了原型式繼承,這個方法接受兩個參數(shù):一個用作新對象原型的對象,另一個(可選的)為新對象定義額外屬性的對象。只傳入一個參數(shù)的情況,和object()方法相同。
// Object.create()只用一個參數(shù) var person = { name: "Nicholas", friends: ["shelby","court","van"] }; var anotherPerson = Object.create(person);
// Object.create()用兩個參數(shù) var person = { name: "Nicholas", friends: ["shelby","court","van"] }; var anotherPerson = Object.create(person, { name:{ value: "Greg" } }); alert(anotherPerson.name); //Greg var yetAnotherPerson = Object.create(person, { // 為新對象定義新的friends屬性,該屬性會覆蓋原型屬性中的friends friends:{ value: ["1","2","3"] } }); alert(yetAnotherPerson.friends); //"1,2,3" // 但是原型對象中的friends屬性仍然被共享 alert(person.friends); //"shelby,court,van" alert(anothorPerson.friends); //"shelby,court,van"5.寄生式繼承
function createAnother(original){ var clone = object(original); // 不能做到函數(shù)復(fù)用,導(dǎo)致效率降低 // 添加新函數(shù),增強對象 clone.sayHi = function(){ alert("hi"); } return clone; } var person = { name: "Nicholas", friends: ["shelby","court","van"] }; var anotherPerson = createAnother(person); anotherPerson.sayHi(); //"hi"6.寄生組合式繼承
組合繼承無論在什么情況下,都會調(diào)用兩次超類型構(gòu)造函數(shù):一次是在創(chuàng)建子類型原型的時候,另一次是在子類型構(gòu)造函數(shù)內(nèi)部。
function SuperType(name){ this.name=name; this.colors=["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()
第一次調(diào)用SuperType構(gòu)造函數(shù)時,SubType.prototype(SubType的原型)會得到兩個屬性:name和colors。當調(diào)用SubType構(gòu)造函數(shù)時,又會調(diào)用一次SuperType構(gòu)造函數(shù),這一次又在新對象上創(chuàng)建了實例屬性name和colors。于是這兩個屬性就屏蔽了原型中的兩個同名屬性
為了避免創(chuàng)建兩次相同的屬性,解決方法——寄生組合式繼承。其基本思想是:不必為了指定子類型的原型而調(diào)用超類型的構(gòu)造函數(shù),我們所需要的無非就是超類型原型的一個副本而已。
function inheritPrototype(subType, superType){ var prototype = object(superType.prototype); prototype.constructor = subType; subType.prototype = prototype; } function SuperType(name){ this.name=name; this.colors = ["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); };
上訴例子只調(diào)用了一次SuperType構(gòu)造函數(shù),因此避免了在SubType.prototype上面創(chuàng)建不必要的、多余的屬性。寄生組合式繼承是引用類型最理想的繼承范式
相比之下,第二段程序少了SubType.prototype = new SuperType();這使得SubType.prototype中沒有了name和colors屬性,實現(xiàn)了避免了在SubType.prototype上面創(chuàng)建不必要的、多余的屬性的目的。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/83389.html
摘要:這種方法也存在這樣的問題如果修改了構(gòu)造函數(shù)的原型對象,之前創(chuàng)建的對象無法通過這種方式來確定類型修改構(gòu)造函數(shù)的原型對象會導(dǎo)致之前創(chuàng)建的對象無法通過這種方式判斷類型判斷對象繼承自哪些父類型使用使用 判斷對象類型的方法 使用原型對象上的constructor屬性來判斷 每個對象的原型上都有一個constructor屬性,指向了其構(gòu)造函數(shù) 注意:對象沒有constructor屬性(除非自己添加...
摘要:原型對象的問題省略了為構(gòu)造函數(shù)傳遞參數(shù),導(dǎo)致了所有實例在默認情況下都取得相同的屬性值。即使有其他代碼會給這個對象添加方法或數(shù)據(jù)成員,但也不可能有別的方法訪問傳入到構(gòu)造函數(shù)中的原始數(shù)據(jù)。 創(chuàng)建對象 1.Object構(gòu)造函數(shù) 創(chuàng)建一個Object的實例,然為其添加屬性和方法(早期創(chuàng)建對象的模式) var person = new Object(); person.name = Nichol...
摘要:私有變量任何在函數(shù)中定義的變量,都可以認為是私有變量,因為在不能再函數(shù)的外部訪問這些變量。我們把有權(quán)訪問私有變量和私有函數(shù)的公有方法稱為特權(quán)方法。模塊模式模塊模式是為單例創(chuàng)建私有變量和特權(quán)方法。 私有變量 任何在函數(shù)中定義的變量,都可以認為是私有變量,因為在不能再函數(shù)的外部訪問這些變量。私有變量包括函數(shù)的參數(shù)、函數(shù)中定義的變量和函數(shù)。我們把有權(quán)訪問私有變量和私有函數(shù)的公有方法稱為特權(quán)方...
摘要:這是因為子類沒有自己的對象,而是繼承父類的對象,然后對其進行加工。 溫馨提示:作者的爬坑記錄,對你等大神完全沒有價值,別在我這浪費生命溫馨提示-續(xù):你們要非得看,我也攔不住,但是至少得準備個支持ES6的Chrome瀏覽器吧?溫馨提示-再續(xù):ES6簡直了,放著不用簡直令人發(fā)指! 書接上回,即便是程序員,也還是能夠通過自己的努力辛辛苦苦找到合適對象的,見前文《javascript對象不完全...
摘要:對象重新認識面向?qū)ο竺嫦驅(qū)ο髲脑O(shè)計模式上看,對象是計算機抽象現(xiàn)實世界的一種方式。除了字面式聲明方式之外,允許通過構(gòu)造器創(chuàng)建對象。每個構(gòu)造器實際上是一個函數(shù)對象該函數(shù)對象含有一個屬性用于實現(xiàn)基于原型的繼承和共享屬性。 title: JS對象(1)重新認識面向?qū)ο? date: 2016-10-05 tags: JavaScript 0x00 面向?qū)ο?從設(shè)計模式上看,對象是...
閱讀 3779·2021-09-02 09:53
閱讀 2758·2021-07-30 14:57
閱讀 3504·2019-08-30 13:09
閱讀 1206·2019-08-29 13:25
閱讀 817·2019-08-29 12:28
閱讀 1463·2019-08-29 12:26
閱讀 1137·2019-08-28 17:58
閱讀 3316·2019-08-26 13:28