摘要:三組合繼承結(jié)合原型鏈方式和借用構(gòu)造函數(shù)方式的有點(diǎn),進(jìn)行改進(jìn)的一種繼承方式。四寄生組合式繼承為了解決組合繼承中子構(gòu)造函數(shù)的原型鏈出現(xiàn)冗余的屬性和方法,引入的一種繼承方式。
說在前面:
為了使代碼更為簡(jiǎn)潔方便理解, 本文中的代碼均將“非核心實(shí)現(xiàn)”部分的代碼移出。
一、原型鏈方式
關(guān)于原型鏈,可點(diǎn)擊《深入淺出,JS原型鏈的工作原理》,本文不再重復(fù)敘述。
思路:讓子構(gòu)造函數(shù)的原型等于父構(gòu)造函數(shù)的實(shí)例
function A() { } A.prototype.fn = function (){ console.log("in A"); } function B() { } B.prototype = new A(); // 讓子構(gòu)造函數(shù)的原型等于父構(gòu)造函數(shù)的實(shí)例 var b = new B(); b.fn(); // in A console.log(b instanceof B); // true console.log(b instanceof A); // true console.log(b instanceof Object); // true
缺陷:如果父構(gòu)造函數(shù)中的屬性為引用類型,則子構(gòu)造函數(shù)的實(shí)例會(huì)出現(xiàn)相互影響的情況;
function A() { this.prop = ["1","2"]; } A.prototype.fn = function (){ console.log(this.prop); } function B() { } B.prototype = new A(); var b1 = new B(); var b2 = new B(); b1.fn(); // ?["1", "2"] b2.fn(); // ?["1", "2"] b1.prop.push("3"); // 子構(gòu)造函數(shù)實(shí)例b1修改繼承過來的屬性 b2.prop.push("4"); // 子構(gòu)造函數(shù)實(shí)例b2修改繼承過來的屬性 b1.fn(); // ["1", "2", "3", "4"] // b2上的修改影響了b1 b2.fn(); // ["1", "2", "3", "4"] // b1上的修改影響了b2
*導(dǎo)致缺陷原因:引用類型,屬性變量保存的是地址指針而非實(shí)際的值,這個(gè)指針指向了一塊用來保存實(shí)際內(nèi)容的地址。實(shí)例化后,所有實(shí)例中變量保存了同一個(gè)指針,均指向同一個(gè)地址,當(dāng)任何一個(gè)實(shí)例通過指針修改地址的內(nèi)容(并非重新賦予新的指針地址或者修改指針指向)時(shí),其他實(shí)例的也會(huì)受到影響。
二、借用構(gòu)造函數(shù)方式
為了解決“原型鏈方式”繼承的缺陷,引入的一種“繼承”方案。
思路:通過call/apply,在子構(gòu)造函數(shù)中調(diào)用父類的構(gòu)造函數(shù)
function A() { this.prop = ["1","2"]; this.fn2 = function () { console.log(this.prop); } } A.prototype.fn = function (){ console.log(this.prop); } function B() { A.call(this); // 通過call/apply,在子構(gòu)造函數(shù)中調(diào)用父類的構(gòu)造函數(shù) } var b1 = new B(); var b2 = new B(); b1.fn2(); //?["1", "2"] b2.fn2(); // ["1", "2"] b1.prop.push("3"); b2.prop.push("4"); b1.fn2(); //?["1", "2", "3"] b2.fn2(); // ["1", "2", "4"] b1.fn(); // 提示異常:b1.fn is not a function console.log(b1 instanceof B); // true console.log(b1 instanceof A); // false console.log(b1 instanceof Object); // true
缺陷:由于“繼承”過程中,A僅充當(dāng)普通函數(shù)被調(diào)用,使得父構(gòu)造函數(shù)A原型無法與形成子構(gòu)造函數(shù)B構(gòu)成原形鏈關(guān)系。因此無法形成繼承關(guān)系:"b1 instanceof A"結(jié)果為false,B的實(shí)例b1亦無法調(diào)用A原型中的方法。實(shí)際意義上,這種不屬于繼承。
三、組合繼承
結(jié)合“原型鏈方式”和“借用構(gòu)造函數(shù)方式”的有點(diǎn),進(jìn)行改進(jìn)的一種繼承方式。
思路:原型上的屬性和方法通過“原型鏈方式”繼承;父構(gòu)造函數(shù)內(nèi)的屬性和方法通過“借用構(gòu)造函數(shù)方式”繼承
function A() { this.prop = ["1","2"]; } A.prototype.fn = function (){ console.log(this.prop); } function B() { A.call(this); // 借用構(gòu)造函數(shù)方式 } B.prototype = new A(); // 原型鏈方式 var b1 = new B(); var b2 = new B(); b1.fn(); //?["1", "2"] b2.fn(); // ["1", "2"] b1.prop.push("3"); b2.prop.push("4"); b1.fn(); //?["1", "2", "3"] b2.fn(); // ["1", "2", "4"] console.log(b1 instanceof B); // true console.log(b1 instanceof A); // true console.log(b1 instanceof Object); // true
缺陷:子構(gòu)造函數(shù)的原型出現(xiàn)一套冗余“父構(gòu)造函數(shù)非原型上的屬性和方法”。上述代碼在執(zhí)行“A.call(this);”時(shí)候,會(huì)給this(即將從B返回給b1賦值的對(duì)象)添加一個(gè)“prop”屬性;在執(zhí)行“B.prototype = new A();”時(shí),又會(huì)通過實(shí)例化的形式給B的原型賦值一次“prop”屬性。顯然,由于實(shí)例屬性方法的優(yōu)先級(jí)高于原型上的屬性方法,絕大多數(shù)情況下,原型上的“prop”是不會(huì)被訪問到的。
四、寄生組合式繼承
為了解決“組合繼承”中子構(gòu)造函數(shù)的原型鏈出現(xiàn)冗余的屬性和方法,引入的一種繼承方式。
思路:在組合繼承的基礎(chǔ)上,通過Object.create的方式實(shí)現(xiàn)原型鏈方式
function A() { this.prop = ["1","2"]; } A.prototype.fn = function (){ console.log(this.prop); } function B() { A.call(this); } B.prototype = Object.create(A.prototype); // Object.create的方式實(shí)現(xiàn)原型鏈方式 var b1 = new B(); var b2 = new B(); b1.fn(); //?["1", "2"] b2.fn(); // ["1", "2"] b1.prop.push("3"); b2.prop.push("4"); b1.fn(); //?["1", "2", "3"] b2.fn(); // ["1", "2", "4"] console.log(b1 instanceof B); // true console.log(b1 instanceof A); // true console.log(b1 instanceof Object); // true
最后補(bǔ)充
1、因?yàn)樽訕?gòu)造函數(shù)的實(shí)例自身沒有constructor屬性,當(dāng)我們?cè)L問實(shí)例的constructor屬性時(shí),實(shí)際是訪問原型的constructor屬性,該屬性應(yīng)該指向(子)構(gòu)造函數(shù)。但是上述例子中,代碼均會(huì)指向父構(gòu)造函數(shù)。為了與ECMAScript規(guī)范保持一致,在所有的“原型鏈繼承”后,應(yīng)當(dāng)將原型的constructor屬性指向子構(gòu)造函數(shù)本身:
B.prototype = .... --> B.prototype.constructor = B; <-- ...
2、Object.create是ECMAScript 5中加入的一個(gè)函數(shù),這個(gè)函數(shù)的功能是:將入?yún)?需為一個(gè)對(duì)象)作為原型,創(chuàng)建并返回一個(gè)新的(只有原型的)的對(duì)象。此功能等價(jià)于:
function object(o){ function F(){} F. prototype = o; return new F(); } // 來源于《JavaScript高級(jí)程序設(shè)計(jì)(第3版)》
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/108850.html
摘要:原型繼承借助父級(jí)對(duì)象,通過構(gòu)造函數(shù)創(chuàng)建一個(gè)以父級(jí)對(duì)象為原型的新對(duì)象這里,直接將父對(duì)象設(shè)置為子對(duì)象的原型,中的方法就是這種實(shí)現(xiàn)方式。構(gòu)造器借用中的和方法非常好用,其改變方法執(zhí)行上下文的功能在繼承的實(shí)現(xiàn)中也能發(fā)揮作用。 不同于基于類的編程語言,如 C++ 和 Java,JavaScript 中的繼承方式是基于原型的。同時(shí)由于 JavaScript 是一門非常靈活的語言,其實(shí)現(xiàn)繼承的方式也非...
摘要:本文重點(diǎn)不要試圖在內(nèi)置類型的子類中重寫方法,可以繼承的可拓展類尋求變通掌握多重繼承中的和了解處理多重繼承的一些建議。子類化的代碼如下輸出小結(jié)上述問題只發(fā)生在語言實(shí)現(xiàn)的內(nèi)置類型子類化情況中,而且只影響直接繼承內(nèi)置類型的自定義類。 導(dǎo)語:本文章記錄了本人在學(xué)習(xí)Python基礎(chǔ)之面向?qū)ο笃闹攸c(diǎn)知識(shí)及個(gè)人心得,打算入門Python的朋友們可以來一起學(xué)習(xí)并交流。 本文重點(diǎn): 1、不要試圖在內(nèi)置...
摘要:繼承理論源于生活又高于生活在中繼承,和現(xiàn)實(shí)生活中繼承是相似的如兒子繼承父親財(cái)產(chǎn)子女的生理特性有父母的特性身高膚色性格等等只是一定比例上是這樣的,不是絕對(duì)的一樣中繼承方法有以下幾種本質(zhì)區(qū)別方法特別注意是本質(zhì)區(qū)別冒充繼承也稱之為借用構(gòu)造函數(shù)這種 JS繼承 理論源于生活、又高于生活 在JS中繼承,和現(xiàn)實(shí)生活中繼承是相似的 如:兒子繼承父親財(cái)產(chǎn)、子女的生理特性有父母的特性(身高、膚色、性格...
摘要:一什么是是一款軟件項(xiàng)目管理和理解工具。基于項(xiàng)目對(duì)象模型的概念,通過添加一小段描述來管理項(xiàng)目的構(gòu)建。另外如果子模塊中指定了版本號(hào),那么會(huì)使用子模塊中指定的版本。 一、什么是Maven? Maven是一款軟件項(xiàng)目管理和理解工具。基于項(xiàng)目對(duì)象模型(POM)的概念,通過添加一小段描述來管理項(xiàng)目的構(gòu)建。 二、為什么要使用Maven? 以前在用Java開發(fā)一個(gè)項(xiàng)目時(shí),往往需要引入幾十或者上百個(gè)Ja...
摘要:本文是本人閱讀學(xué)習(xí)深入理解原型和閉包時(shí)所作的總結(jié)和筆記,當(dāng)然也引用了很多原文,感興趣的朋友也可以直接去看原文。即這里的稱為隱式原型。注意,構(gòu)造函數(shù)的函數(shù)名第一個(gè)字母大寫規(guī)則約定。但實(shí)際上,上述情況是一種理想的情況。 本文是本人閱讀學(xué)習(xí)深入理解JavaScript原型和閉包時(shí)所作的總結(jié)和筆記,當(dāng)然也引用了很多原文,感興趣的朋友也可以直接去看原文。 1、一切都是對(duì)象 先說結(jié)論,一切引用類型...
閱讀 2101·2023-04-25 17:23
閱讀 2919·2021-11-17 09:33
閱讀 2513·2021-08-21 14:09
閱讀 3579·2019-08-30 15:56
閱讀 2605·2019-08-30 15:54
閱讀 1623·2019-08-30 15:53
閱讀 2126·2019-08-29 13:53
閱讀 1141·2019-08-29 12:31