摘要:因而可更改為增加屬性這種寫法要注意,創(chuàng)建實例一定要在定義原型之后,因為重寫原型對象就切斷了構(gòu)造函數(shù)與最初原型的聯(lián)系。借用構(gòu)造函數(shù)的問題還是和構(gòu)造函數(shù)創(chuàng)建對象一樣,方法都在構(gòu)造函數(shù)定義,函數(shù)復用就無從談起了。
一.創(chuàng)建對象
雖然Object構(gòu)造函數(shù)或?qū)ο笞置媪靠梢杂脕韯?chuàng)建單個對象,但有個明顯缺點:使用同一個接口創(chuàng)建很多對象會產(chǎn)生大量重復代碼。因而大家開始探索其他方式。
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);
工廠模式特點:雖然解決了創(chuàng)建多個相似對象的問題,但卻無法識別一個對象的類型。(instance of)
2.構(gòu)造函數(shù)模式
function Person (name, age) { this.name = name; this.age = age; this.sayName = function () { console.log(this.name); } } var person = new Person("Lily", 12); //使用構(gòu)造函數(shù)模式創(chuàng)建實例,必須使用new操作符。
構(gòu)造函數(shù)模式特點:可以將它的實例標識為一種特定類型,但每個方法都要在實力上重新創(chuàng)建一遍。
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了。(無論何時創(chuàng)建一個新函數(shù)A,都會為它創(chuàng)建一個prototype屬性,指向函數(shù)的原型對象,默認情況下,所有原型對象都會獲得一個constructor屬性,包含一個指向A的指針。)
因而可更改為:
function Person () {} Person.prototype = { constructor: Person, //增加constructor屬性 name: "Lily", age: 12, sayName: function () { console.log(this.name); } } //這種寫法要注意,創(chuàng)建實例一定要在定義原型之后,因為重寫原型對象就切斷了構(gòu)造函數(shù)與最初原型的聯(lián)系。
原型模式的特點:實現(xiàn)了讓所有實例共享原型對象所包含的屬性和方法。但缺點也在于這種共享對于包含引用類型值的屬性而言,存在一些問題,即所有實例會共享一個數(shù)組或者對象。
4.組合構(gòu)造函數(shù)模式和原型模式
function Person (name, age) { this.name = name; this.age = age; this.friends = ["Tom", "Bob"]; } Person.prototype = { constructor: Person, sayName: function () { console.log(this.name); } }
構(gòu)造函數(shù)模式用于定義實例屬性,而原型模式用于定義方法和共享的屬性。這是目前最廣泛,認同度最高的方法。
5.動態(tài)原型模式
有其他OO語言經(jīng)驗的開發(fā)人員看到獨立的構(gòu)造函數(shù)和原型,可能會困惑。動態(tài)原型模式則是致力于解決此問題的一個方案,它把所有信息都封裝在了構(gòu)造函數(shù)中,在必要情況下,通過在構(gòu)造函數(shù)中初始化原型,保持了組合使用構(gòu)造函數(shù)和原型的優(yōu)點。
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語句只需檢查一個初始化應(yīng)該存在的共享屬性或方法即可。 }
使用動態(tài)原型模式要記得不能用對象字面量重寫原型,因為如果在創(chuàng)建了實例的情況下重寫原型。那么就會切斷現(xiàn)有實例與新原型的聯(lián)系。
關(guān)于寄生構(gòu)造模式和穩(wěn)妥構(gòu)造模式,在工程實踐用的不多且稍顯過時,就不贅述了。有時間可以了解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; }
需要注意的是,在通過原型鏈實現(xiàn)繼承時,不能用對象字面量創(chuàng)建原型方法,因為這樣會重寫原型鏈。如下所示:
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中定義一個數(shù)組colors,當subType通過原型鏈繼承SuperType后,它也會擁有一個colors屬性(就像專門創(chuàng)建了一個subType.prototype.colors屬性一樣),結(jié)果是SubType所有實例都會共享這個屬性。對其中一個實例.colors屬性會影響到所有其他實例。
2.在創(chuàng)建子類型的實例時,沒辦法在不影響所有對象實例的情況下,向超類型的構(gòu)造函數(shù)傳遞參數(shù)。
因此實踐中很少多帶帶使用原型鏈繼承。
2.借用構(gòu)造函數(shù)
function SuperType (name) { this.name = name; this.colors = ["red", "blue", "yellow"]; } function SubType () SuperType.call(this, "Lily"); this.age = 12; } //使用這種方式就可以向超類型的構(gòu)造函數(shù)傳參啦。
借用構(gòu)造函數(shù)的問題:還是和構(gòu)造函數(shù)創(chuàng)建對象一樣,方法都在構(gòu)造函數(shù)定義,函數(shù)復用就無從談起了。
3.組合繼承
使用原型鏈實現(xiàn)對原型屬性和方法的繼承,而通過構(gòu)造函數(shù)實現(xiàn)對實例屬性的繼承。
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); //第二次調(diào)用SuperType() this.age = age; } //繼承方法 SubType.prototype = new SuperType(); //第一次調(diào)用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"
組合繼承避免了原型鏈和借用構(gòu)造函數(shù)的缺陷,是一種較為流行的繼承方式。但是它還存在一個缺點:在第一次調(diào)用superType時,SubType.prototype會得到兩個屬性:name和colors,當調(diào)用SubType的構(gòu)造函數(shù)時又會再調(diào)用一次SuperType構(gòu)造函數(shù),在對象實例上創(chuàng)建了實例屬性name和colors屏蔽了SubType原型中的同名屬性。
寄生組合式繼承
寄生組合式是組合式繼承的改進,思路是不必為了指定子類的原型而調(diào)用超類的構(gòu)造函數(shù),僅復制超類的原型即可。
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); }
開發(fā)人員普遍認為寄生組合式繼承是引用類型最理想的繼承方法。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/97987.html
摘要:子類繼承自父類的方法可以重新定義即覆寫,被調(diào)用時會使用子類定義的方法什么是多態(tài)青蛙是一個對象,金魚也是一個對象,青蛙會跳,金魚會游,定義好對象及其方法后,我們能用青蛙對象調(diào)用跳這個方法,也能用金魚對象調(diào)用游這個方法。 1、專用術(shù)語 面向?qū)ο缶幊坛绦蛟O(shè)計簡稱:OOP,在面向?qū)ο缶幊讨谐S玫降母拍钣校簩ο?、屬性、方法、類、封裝、聚合、重用與繼承、多態(tài)。 2、什么是對象? 面向?qū)ο缶幊痰闹攸c...
摘要:上一篇你不知道的筆記寫在前面這是年第一篇博客,回顧去年年初列的學習清單,發(fā)現(xiàn)僅有部分完成了。當然,這并不影響年是向上的一年在新的城市穩(wěn)定連續(xù)堅持健身三個月早睡早起游戲時間大大縮減,學會生活。 上一篇:《你不知道的javascript》筆記_this 寫在前面 這是2019年第一篇博客,回顧去年年初列的學習清單,發(fā)現(xiàn)僅有部分完成了。當然,這并不影響2018年是向上的一年:在新的城市穩(wěn)定、...
摘要:的繼承方式屬于原型式繼承,非常靈活。當使用關(guān)鍵字執(zhí)行類的構(gòu)造函數(shù)時,系統(tǒng)首先創(chuàng)建一個新對象,這個對象會繼承自構(gòu)造函數(shù)的原型對象新對象的原型就是構(gòu)造函數(shù)的屬性。也就是說,構(gòu)造函數(shù)用來對生成的新對象進行一些處理,使這個新對象具有某些特定的屬性。 繼承這個東西在Javascript中尤其復雜,我掌握得也不好,找工作面試的時候在這個問題上栽過跟頭。Javascript的繼承方式屬于原型式繼承,...
摘要:繼承的是超類型中構(gòu)造函數(shù)中的屬性,如上繼承了屬性,但沒有繼承原型中的方法。上述造成的結(jié)果是子類型實例中有兩組超類型的構(gòu)造函數(shù)中定義的屬性,一組在子類型的實例中,一組在子類型實例的原型中。 ECMAScript只支持實現(xiàn)繼承,主要依靠原型鏈來實現(xiàn)。與實現(xiàn)繼承對應(yīng)的是接口繼承,由于script中函數(shù)沒有簽名,所以無法實現(xiàn)接口繼承。 一、原型鏈 基本思想:利用原型讓一個引用類型繼承另一個引用...
摘要:繼承原型鏈如果構(gòu)造函數(shù)或?qū)ο蟮脑椭赶驑?gòu)造函數(shù)或?qū)ο螅脑驮僦赶驑?gòu)造函數(shù)或?qū)ο?,以此類推,最終的構(gòu)造函數(shù)或?qū)ο蟮脑椭赶虻脑汀? 繼承 原型鏈 如果構(gòu)造函數(shù)或?qū)ο驛的原型指向構(gòu)造函數(shù)或?qū)ο驜,B的原型再指向構(gòu)造函數(shù)或?qū)ο驝,以此類推,最終的構(gòu)造函數(shù)或?qū)ο蟮脑椭赶騉bject的原型。由此形成了一條鏈狀結(jié)構(gòu),被稱之為原型鏈。按照上述的描述,在B中定義的屬性或方法,可以在A中使用并不需要...
閱讀 1514·2021-10-11 10:59
閱讀 1887·2021-09-09 11:36
閱讀 1402·2019-08-30 15:55
閱讀 1332·2019-08-29 11:20
閱讀 3067·2019-08-26 13:39
閱讀 1472·2019-08-26 13:37
閱讀 1966·2019-08-26 12:11
閱讀 1328·2019-08-23 14:28