摘要:因而可更改為增加屬性這種寫法要注意,創建實例一定要在定義原型之后,因為重寫原型對象就切斷了構造函數與最初原型的聯系。借用構造函數的問題還是和構造函數創建對象一樣,方法都在構造函數定義,函數復用就無從談起了。
一.創建對象
雖然Object構造函數或對象字面量可以用來創建單個對象,但有個明顯缺點:使用同一個接口創建很多對象會產生大量重復代碼。因而大家開始探索其他方式。
1.工廠模式
function createPerson (name, age) { var o = new Object(): o.name = name; o.age = age; o.sayName = function () { console.log(this.name); } return o; } var person = createPerson("Lily", 12);
工廠模式特點:雖然解決了創建多個相似對象的問題,但卻無法識別一個對象的類型。(instance of)
2.構造函數模式
function Person (name, age) { this.name = name; this.age = age; this.sayName = function () { console.log(this.name); } } var person = new Person("Lily", 12); //使用構造函數模式創建實例,必須使用new操作符。
構造函數模式特點:可以將它的實例標識為一種特定類型,但每個方法都要在實力上重新創建一遍。
3.原型模式
function Person () {} Person.prototype.name = "Lily"; Person.prototype.age = 12; Person.prototype.sayName = function () { console.log(this.name); } var person = new Person(); //使用hasOwnProperty方法可以檢測一個屬性存在于實例還是原型。 console.log(person.hasOwnProperty("name")); //false person.name = "Tom"; //來自實例 console.log(person.hasOwnProperty("name")); //true
更簡單的原型語法:
function Person () {} Person.prototype = { name: "Lily", age: 12, sayName: function () { console.log(this.name); } } //這樣寫會導致constructor屬性不再指向Person了。(無論何時創建一個新函數A,都會為它創建一個prototype屬性,指向函數的原型對象,默認情況下,所有原型對象都會獲得一個constructor屬性,包含一個指向A的指針。)
因而可更改為:
function Person () {} Person.prototype = { constructor: Person, //增加constructor屬性 name: "Lily", age: 12, sayName: function () { console.log(this.name); } } //這種寫法要注意,創建實例一定要在定義原型之后,因為重寫原型對象就切斷了構造函數與最初原型的聯系。
原型模式的特點:實現了讓所有實例共享原型對象所包含的屬性和方法。但缺點也在于這種共享對于包含引用類型值的屬性而言,存在一些問題,即所有實例會共享一個數組或者對象。
4.組合構造函數模式和原型模式
function Person (name, age) { this.name = name; this.age = age; this.friends = ["Tom", "Bob"]; } Person.prototype = { constructor: Person, sayName: function () { console.log(this.name); } }
構造函數模式用于定義實例屬性,而原型模式用于定義方法和共享的屬性。這是目前最廣泛,認同度最高的方法。
5.動態原型模式
有其他OO語言經驗的開發人員看到獨立的構造函數和原型,可能會困惑。動態原型模式則是致力于解決此問題的一個方案,它把所有信息都封裝在了構造函數中,在必要情況下,通過在構造函數中初始化原型,保持了組合使用構造函數和原型的優點。
function Person (name, age) { this.name = name; this.age = age; this.friends = ["Tom", "Bob"]; if (type of this.sayName != "function") { Person.prototype.sayName = function () { console.log(this.name); } } //if語句只需檢查一個初始化應該存在的共享屬性或方法即可。 }
使用動態原型模式要記得不能用對象字面量重寫原型,因為如果在創建了實例的情況下重寫原型。那么就會切斷現有實例與新原型的聯系。
關于寄生構造模式和穩妥構造模式,在工程實踐用的不多且稍顯過時,就不贅述了。有時間可以了解es6的class。
二.繼承
1.原型鏈
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function () { return this.property; } function SubType(){ this.property = false; } SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function () { return this.property; }
需要注意的是,在通過原型鏈實現繼承時,不能用對象字面量創建原型方法,因為這樣會重寫原型鏈。如下所示:
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function () { return this.property; } function SubType(){ this.property = false; } SubType.prototype = new SuperType(); SubType.prototype = { getSubValue: function () { return this.subproperty; }, someOtherMethod: function () { return false; } } //這樣會導致SubType的實例無法訪問到getSuperValue()方法了。
原型鏈繼承的問題:
1.共享實例屬性,如果SupeType中定義一個數組colors,當subType通過原型鏈繼承SuperType后,它也會擁有一個colors屬性(就像專門創建了一個subType.prototype.colors屬性一樣),結果是SubType所有實例都會共享這個屬性。對其中一個實例.colors屬性會影響到所有其他實例。
2.在創建子類型的實例時,沒辦法在不影響所有對象實例的情況下,向超類型的構造函數傳遞參數。
因此實踐中很少多帶帶使用原型鏈繼承。
2.借用構造函數
function SuperType (name) { this.name = name; this.colors = ["red", "blue", "yellow"]; } function SubType () SuperType.call(this, "Lily"); this.age = 12; } //使用這種方式就可以向超類型的構造函數傳參啦。
借用構造函數的問題:還是和構造函數創建對象一樣,方法都在構造函數定義,函數復用就無從談起了。
3.組合繼承
使用原型鏈實現對原型屬性和方法的繼承,而通過構造函數實現對實例屬性的繼承。
function SuperType (name) { this.name = name; this.colors = ["red", "blue", "yellow"]; } SuperType.prototype.sayName = function () { console.log(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 () { console.log(this.age); } var instance1 = new SubType("Lily", 12); instance1.colors.push("green"); console.log(instance1.colors); // "red,blue,yellow,green" var instance2 = new SubType("Lucy", 22); console.log(instance1.colors); // "red,blue,yellow"
組合繼承避免了原型鏈和借用構造函數的缺陷,是一種較為流行的繼承方式。但是它還存在一個缺點:在第一次調用superType時,SubType.prototype會得到兩個屬性:name和colors,當調用SubType的構造函數時又會再調用一次SuperType構造函數,在對象實例上創建了實例屬性name和colors屏蔽了SubType原型中的同名屬性。
寄生組合式繼承
寄生組合式是組合式繼承的改進,思路是不必為了指定子類的原型而調用超類的構造函數,僅復制超類的原型即可。
function SuperType (name) { this.name = name; this.colors = ["red", "blue", "yellow"]; } SuperType.prototype.sayName = function () { console.log(this.name); }; function SubType (name, age) // 繼承實例屬性 SuperType.call(this, name); this.age = age; } //繼承方法 SubType.prototype = Object.create(SuperType.prototype); //Object.create(obj)相當于 function F(){}; F.prototype = obj;return new F(); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function () { console.log(this.age); }
開發人員普遍認為寄生組合式繼承是引用類型最理想的繼承方法。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/97987.html
摘要:子類繼承自父類的方法可以重新定義即覆寫,被調用時會使用子類定義的方法什么是多態青蛙是一個對象,金魚也是一個對象,青蛙會跳,金魚會游,定義好對象及其方法后,我們能用青蛙對象調用跳這個方法,也能用金魚對象調用游這個方法。 1、專用術語 面向對象編程程序設計簡稱:OOP,在面向對象編程中常用到的概念有:對象、屬性、方法、類、封裝、聚合、重用與繼承、多態。 2、什么是對象? 面向對象編程的重點...
摘要:上一篇你不知道的筆記寫在前面這是年第一篇博客,回顧去年年初列的學習清單,發現僅有部分完成了。當然,這并不影響年是向上的一年在新的城市穩定連續堅持健身三個月早睡早起游戲時間大大縮減,學會生活。 上一篇:《你不知道的javascript》筆記_this 寫在前面 這是2019年第一篇博客,回顧去年年初列的學習清單,發現僅有部分完成了。當然,這并不影響2018年是向上的一年:在新的城市穩定、...
摘要:的繼承方式屬于原型式繼承,非常靈活。當使用關鍵字執行類的構造函數時,系統首先創建一個新對象,這個對象會繼承自構造函數的原型對象新對象的原型就是構造函數的屬性。也就是說,構造函數用來對生成的新對象進行一些處理,使這個新對象具有某些特定的屬性。 繼承這個東西在Javascript中尤其復雜,我掌握得也不好,找工作面試的時候在這個問題上栽過跟頭。Javascript的繼承方式屬于原型式繼承,...
摘要:繼承的是超類型中構造函數中的屬性,如上繼承了屬性,但沒有繼承原型中的方法。上述造成的結果是子類型實例中有兩組超類型的構造函數中定義的屬性,一組在子類型的實例中,一組在子類型實例的原型中。 ECMAScript只支持實現繼承,主要依靠原型鏈來實現。與實現繼承對應的是接口繼承,由于script中函數沒有簽名,所以無法實現接口繼承。 一、原型鏈 基本思想:利用原型讓一個引用類型繼承另一個引用...
摘要:繼承原型鏈如果構造函數或對象的原型指向構造函數或對象,的原型再指向構造函數或對象,以此類推,最終的構造函數或對象的原型指向的原型。 繼承 原型鏈 如果構造函數或對象A的原型指向構造函數或對象B,B的原型再指向構造函數或對象C,以此類推,最終的構造函數或對象的原型指向Object的原型。由此形成了一條鏈狀結構,被稱之為原型鏈。按照上述的描述,在B中定義的屬性或方法,可以在A中使用并不需要...
閱讀 1496·2021-10-11 10:59
閱讀 1857·2021-09-09 11:36
閱讀 1370·2019-08-30 15:55
閱讀 1322·2019-08-29 11:20
閱讀 3057·2019-08-26 13:39
閱讀 1458·2019-08-26 13:37
閱讀 1951·2019-08-26 12:11
閱讀 1313·2019-08-23 14:28