摘要:面向對象高級繼承模式一原型鏈繼承方式原型鏈繼承流程定義父類型構造函數。缺點無法避免構造函數模式存在的問題方法都在構造函數中定義,無法函數復用。六寄生組合式繼承在這里重復一下組合繼承的代碼組合繼承最大的缺點是會調用兩次父構造函數。
JavaScript 面向對象高級——繼承模式 一、原型鏈繼承
方式1: 原型鏈繼承
(1)流程:
? 1、定義父類型構造函數。
? 2、給父類型的原型添加方法。
? 3、定義子類型的構造函數。
? 4、創(chuàng)建父類型的對象賦值給子類型的原型。
? 5、將子類型原型的構造屬性設置為子類型。
? 6、給子類型原型添加方法。
? 7、創(chuàng)建子類型的對象: 可以調用父類型的方法。
(2)關鍵:
子類型的原型為父類型的一個實例對象
// 1.定義父類型構造函數 function Supper() { this.supProp = "Supper property" } // 2.給父類型的原型添加方法 Supper.prototype.showSupperProp = function () { console.log(this.supProp) } // 3.定義子類型的構造函數 function Sub() { this.subProp = "Sub property" } // 4.子類型的原型為父類型的一個實例對象 Sub.prototype = new Supper() // 5.將子類型原型的構造屬性constructor指向子類型 Sub.prototype.constructor = Sub // 6.給子類型原型添加方法 Sub.prototype.showSubProp = function () { console.log(this.subProp) } // 7.創(chuàng)建子類型的對象,可以調用父類型的方法 var sub = new Sub() sub.showSupperProp() // Supper property sub.showSubProp() // Sub property console.log(sub) // Sub
(3)缺點:
1、包含引用類型值的原型,由于實例共享屬性,一個實例對原型屬性的修改會在另一個實例中反映出來。
2、不能向超類型的構造函數中傳遞參數。
二、借用構造函數繼承方式2: 借用構造函數繼承。
(1)流程:
? 1、定義父類型構造函數。
? 2、定義子類型構造函數。
? 3、在子類型構造函數中調用父類型構造。
// 1.定義父類型構造函數 function Person(name, age) { this.name = name this.age = age } // 2.定義子類型構造函數 function Student(name, age, price) { // 3.在子類型構造函數中調用父類型構造 Person.call(this, name, age) // 相當于: this.Person(name, age) /*this.name = name this.age = age*/ this.price = price } var s = new Student("Tom", 20, 14000) console.log(s.name, s.age, s.price) // Tom 20 14000
(2)關鍵:
在子類型構造函數中通過call()調用父類型構造函數。
(3)缺點:
1、無法避免構造函數模式存在的問題——方法都在構造函數中定義,無法函數復用。
2、在父類型原型中定義的方法在子類型中是不可見的,只能繼承父類型構造函數中定義的屬性和方法。
三、組合繼承方式3: 原型鏈+借用構造函數的組合繼承。
1、利用原型鏈實現對父類型對象的方法繼承。
2、利用call()借用父類型構造函數初始化相同屬性。
function Person(name, age) { this.name = name this.age = age } Person.prototype.setName = function (name) { this.name = name } function Student(name, age, price) { Person.call(this, name, age) // 為了得到屬性 this.price = price } Student.prototype = new Person() // 為了能看到父類型的方法 Student.prototype.constructor = Student //修正constructor屬性 Student.prototype.setPrice = function (price) { this.price = price } var s = new Student("Tom", 24, 15000) s.setName("Bob") s.setPrice(16000) console.log(s.name, s.age, s.price)四、原型式繼承
function createObj(o) { function F(){} F.prototype = o; return new F(); }
就是 ES5 Object.create 的模擬實現,將傳入的對象作為創(chuàng)建的對象的原型。
缺點:包含引用類型的屬性值始終都會共享相應的值,這點跟原型鏈繼承一樣。
var person = { name: "kevin", friends: ["daisy", "kelly"] } var person1 = createObj(person); var person2 = createObj(person); person1.name = "person1"; console.log(person2.name); // kevin person1.firends.push("taylor"); console.log(person2.friends); // ["daisy", "kelly", "taylor"]
注意:修改person1.name的值,person2.name的值并未發(fā)生改變,并不是因為person1和person2有獨立的 name 值,而是因為person1.name = "person1",給person1添加了 name 值,并非修改了原型上的 name 值。
五、寄生式繼承創(chuàng)建一個僅用于封裝繼承過程的函數,該函數在內部以某種形式來做增強對象,最后返回對象。
function createObj (o) { var clone = Object.create(o); clone.sayName = function () { console.log("hi"); } return clone; }
缺點:跟借用構造函數模式一樣,每次創(chuàng)建對象都會創(chuàng)建一遍方法。
六、寄生組合式繼承在這里重復一下組合繼承的代碼:
function Parent (name) { this.name = name; this.colors = ["red", "blue", "green"]; } Parent.prototype.getName = function () { console.log(this.name) } function Child (name, age) { Parent.call(this, name); this.age = age; } Child.prototype = new Parent(); var child1 = new Child("kevin", "18"); console.log(child1)
組合繼承最大的缺點是會調用兩次父構造函數。
一次是設置子類型實例的原型的時候:
Child.prototype = new Parent();
一次在創(chuàng)建子類型實例的時候:
var child1 = new Child("kevin", "18");
回想下 new 的模擬實現,其實在這句中,我們會執(zhí)行:
Parent.call(this, name);
在這里,我們又會調用了一次 Parent 構造函數。
所以,在這個例子中,如果我們打印 child1 對象,我們會發(fā)現 Child.prototype 和 child1 都有一個屬性為colors,屬性值為["red", "blue", "green"]。
那么我們該如何精益求精,避免這一次重復調用呢?
如果我們不使用 Child.prototype = new Parent() ,而是間接的讓 Child.prototype 訪問到 Parent.prototype 呢?
看看如何實現:
function Parent (name) { this.name = name; this.colors = ["red", "blue", "green"]; } Parent.prototype.getName = function () { console.log(this.name) } function Child (name, age) { Parent.call(this, name); this.age = age; } // 關鍵的三步 var F = function () {}; F.prototype = Parent.prototype; Child.prototype = new F(); var child1 = new Child("kevin", "18"); console.log(child1);
最后我們封裝一下這個繼承方法:
function object(o) { function F() {} F.prototype = o; return new F(); } function prototype(child, parent) { var prototype = object(parent.prototype); prototype.constructor = child; child.prototype = prototype; } // 當我們使用的時候: prototype(Child, Parent);
引用《JavaScript高級程序設計》中對寄生組合式繼承的夸贊就是:
這種方式的高效率體現它只調用了一次 Parent 構造函數,并且因此避免了在 Parent.prototype 上面創(chuàng)建不必要的、多余的屬性。與此同時,原型鏈還能保持不變;因此,還能夠正常使用 instanceof 和 isPrototypeOf。開發(fā)人員普遍認為寄生組合式繼承是引用類型最理想的繼承范式。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105094.html
摘要:類類的概念應該是面向對象語言的一個特色,但是并不像,等高級語言那樣擁有正式的類,而是多數通過構造器以及原型方式來仿造實現。因此,出現了構造函數方式,它的關鍵在于構造器概念的引入。于是,這就產生了構造函數原型法的類構造方法。 類 Class 類的概念應該是面向對象語言的一個特色,但是JavaScript并不像Java,C++等高級語言那樣擁有正式的類,而是多數通過構造器以及原型方式...
摘要:實現思路使用原型鏈實現對原型方法和方法的繼承,而通過借用構造函數來實現對實例屬性的繼承。繼承屬性繼承方法以上代碼,構造函數定義了兩個屬性和。 JS面向對象的程序設計之繼承的實現-組合繼承 前言:最近在細讀Javascript高級程序設計,對于我而言,中文版,書中很多地方翻譯的差強人意,所以用自己所理解的,嘗試解讀下。如有紕漏或錯誤,會非常感謝您的指出。文中絕大部分內容引用自《Java...
摘要:構造函數模式這種方法創(chuàng)建自定義的構造函數,從而自定義對象類型的屬性和方法。借用構造函數在子類型構造函數的內部調用超類型構造函數,通過和方法來實現。 JavaScript中沒有類的概念,它不是嚴格意義上的面向對象語言,而是基于對象(Object-based)的編程語言。下面是讀《JavaScript高級程序設計(第三版)》的學習筆記,總結一些常用的創(chuàng)建對象和繼承的方法。 一、創(chuàng)建對象 1...
摘要:無限增殖返回蘋果返回香蕉返回返回使用的新語法方法會創(chuàng)建一個新對象,使用現有的對象來提供新創(chuàng)建的對象的。是新增的,用來規(guī)范原型式繼承。這里將返回的新對象放到子類的原型對象里面,這樣子類就擁有了父類的原型對象,也就實現了方法的繼承。 這是最后的最后了,我會順便總結一下各種繼承方式的學習和理解。(老板要求什么的,管他呢) 一、繼承-組合繼承、偽經典繼承 showImg(https://seg...
摘要:請記住,這些書中的一些可能不是最新的,但概念和基礎仍應適用。是最好的老師之一。的秘密由部分組成。在你完成這些書后,查看書籍和最好的本土書籍。 我看過三本,第1本,第二本,第四本。第一本買的的實體書,其他兩本看的是電子書。第一本是大名鼎鼎老道寫的,書很薄,但是非常經典。javascirpt忍者秘籍是jquery的作者寫的,也是非常經典。you dont kown js系列也是非常好。看了...
閱讀 3816·2021-11-18 13:19
閱讀 1169·2021-10-11 10:58
閱讀 3278·2019-08-29 16:39
閱讀 3130·2019-08-26 12:08
閱讀 2026·2019-08-26 11:33
閱讀 2453·2019-08-23 18:30
閱讀 1298·2019-08-23 18:21
閱讀 2515·2019-08-23 18:18