摘要:對象經典對象創建與繼承模式組合模式創建對象中創建一個對象的方式多種多樣,每種方式都有自己缺點或者優點,具體的可以參考而組合使用構造函數模式和原型模式來創建自定義類型算是最常見的方式了。
title: JS對象(3)經典對象創建與繼承模式
date: 2016-09-28
tags: JavaScript
JS 中創建一個對象的方式多種多樣,每種方式都有自己缺點或者優點,具體的可以參考____
而組合使用構造函數模式和原型模式來創建自定義類型算是最常見的方式了。
在組合模式中,構造函數用于定義實例屬性,而原型用于定義方法和共享的屬性。
如此,每個實例都會有自己的一份實例屬性的副本,又共享著對方法的引用。
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.friends = ["jack", "marli"] } Person.prototype = { // 使用字面量形式重寫原型 constructor : Person, sayName : function(){ console.log(this.name); } } var person1 = new Person("劉德華",54,"歌手 演員") person1.friends.push("成龍") var person2 = new Person("特朗普",60,"企業家 花花公子 總統") console.log(person1.sayName()+"的朋友: "+person1.friends) //劉德華的朋友: jack,marli,成龍 console.log(person2.name+"的朋友: " +person2.friends) //特朗普的朋友: jack,marli
當修改了 person1.friends 并不會影響到 person2.friends,因為它們分別引用了不同的數組。
現在,對 Person 的原型進行如下修改:
Person.prototype = { // 使用字面量形式重寫原型 constructor : Person, sex:"man", hobby:["woman","money","food"], sayName : function(){ console.log(this.name); } }
如上,我們新添加了 sex 和 hobby 兩個共享屬性。
person1.sex = "woman" console.log(person1.sex) // woman console.log(person2.sex) // man person1.hobby.push("reputation") // ["woman", "money", "food", "reputation"] console.log(person2.hobby) // ["woman", "money", "food", "reputation"]
我們嘗試在 person1 中將 Person 原型里的 sex 修改為 woman,person2 并沒有受到影響,即使 sex 屬性是屬于 Person 原型中的共享屬性。這很容易理解,因為 Person 中的 sex 是字符串,即屬于六種原始類型中的一種。
但是,當我門對 person1 中的 hobby 推入一個元素的時候,person2 中 hobby 同樣被更改了。這也很容易理解,hobby 數數組,是引用類型的,且存在于 Person 的原型中,即它是共享屬性,那么在任何實例中的操作都會影響到原型中的共享屬性。
0x02 組合式繼承作為經典繼承模式,組合式繼承模式算是 JS 中使用最多的了。
其思想是使用原型鏈實現對原型屬性和方法的繼承,而通過借用構造函數來實現對實例屬性的繼承。
function SuperType(name){ this.name = name; this.colors = ["red","blue","pink"]; } SuperType.prototype = { // 重寫原型 constructor: SuperType, // 將原型的構造函數指向 SuperType job:["teacher","student"], sayName:function(){ console.log(this.name) } } function SubType(name, age){ SuperType.call(this, name); // **第二次調用 SuperType 構造函數** // 繼承父類的實例屬性,也因此而覆蓋了原型繼承中的同名屬性 this.age = age; } SubType.prototype = new SuperType(); // **第一次調用 Supertype 構造函數** // 此時 SubType 的原型中將會包含 SuperType 的所有屬性和方法(包括實例屬性,共享屬性,以及共享方法) SubType.constructor = SubType; SubType.prototype.sayAge = function(){ // 繼承而來的原型不能通過對象字面量的方式被重寫,即是添加了 constructor 屬性也沒用 console.log(this.age) } var aSubType = new SubType("jack", 24) aSubType.sayName() // jack var aSuperType = new SuperType("mack",35) aSubType.job.push("softfore engineering") console.log(aSuperType.job) // ["teacher", "student", "softfore engineering"] console.log(aSubType.job) // ["teacher", "student", "softfore engineering"]
如下,我們大概了解了組合式繼承,但,正如星號(**)所標記的那樣,組合繼承存在一個不足的地方,就是無論在何種情況下,都會調用兩次超類型構函數。一次是在創建子類型原型的時候,一次是在子類型構造函數內部。
如何想解決這個問題,可以進一步的使用寄生組合式繼承模式,它被認為是引用類型最理想的繼承范式,也是實現基于類型繼承的最有效方式。
0x03 寄生組合式繼承使用寄生組合式繼承可以不必為了指定子類型的原型而調用超類型的構造函數,我們所需要的無非是超類型的一個副本而已。
如下是寄生組合式繼承的基本模式:
function inheritPrototype(subType, superType){ var prototype = Object(superType.prototype) // 創建對象 prototype.constructor = subType; // 增強對象 subType.prototype = prototype; // 指定對象 }
inheritPrototype() 函數接受兩個參數:子類型構造函數和超類型構造函數。在函數中我們首先創建了一個超類型原型的一個副本,然后為創建的副本添加 constructor 屬性,從而彌補因重寫原型而失去的默認的 constructor 屬性,最后我們將新創建的對象(原型副本)賦給子類型的原型。
如此,便可以使用 inheritPrototype() 函數替換組合式繼承模式中為子類原型賦值的操作了
function SuperType(name){ this.name = name; this.colors = ["red","blue","pink"]; } SuperType.prototype = { // 重寫原型 constructor: SuperType, // 將原型的構造函數指向 SuperType job:["teacher","student"], sayName:function(){ console.log(this.name) } } function SubType(name, age){ SuperType.call(this, name); this.age = age; } function inheritPrototype(subType, superType){ var prototype = Object(superType.prototype) // 拷貝父級對象原型 prototype.constructor = subType; //將子類原型構造屬性指向其子類構造函數 subType.prototype = prototype; // 指定對象 } inheritPrototype(SubType, SuperType); var aSubType = new SubType("jack", 24) aSubType.sayName() // jack console.log(aSubType.colors) //["red", "blue", "pink"]
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86515.html
摘要:只要沒有被覆蓋的話對象原型的屬性就能在所有的實例中找到,若整個原型鏈未找到則返回如何實現繼承構造繼承原型繼承實例繼承拷貝繼承原型機制或和方法去實現較簡單,建議使用構造函數與原型混合方式。 HTML相關問題 1.XHTML和HTML有什么區別 HTML是一種基本的WEB網頁設計語言,XHTML是一個基于XML的標記語言最主要的不同:XHTML 元素必須被正確地嵌套。XHTML 元素必須被...
摘要:只要沒有被覆蓋的話對象原型的屬性就能在所有的實例中找到,若整個原型鏈未找到則返回如何實現繼承構造繼承原型繼承實例繼承拷貝繼承原型機制或和方法去實現較簡單,建議使用構造函數與原型混合方式。 HTML相關問題 1.XHTML和HTML有什么區別 HTML是一種基本的WEB網頁設計語言,XHTML是一個基于XML的標記語言最主要的不同:XHTML 元素必須被正確地嵌套。XHTML 元素必須被...
摘要:只要沒有被覆蓋的話對象原型的屬性就能在所有的實例中找到,若整個原型鏈未找到則返回如何實現繼承構造繼承原型繼承實例繼承拷貝繼承原型機制或和方法去實現較簡單,建議使用構造函數與原型混合方式。 HTML相關問題 1.XHTML和HTML有什么區別 HTML是一種基本的WEB網頁設計語言,XHTML是一個基于XML的標記語言最主要的不同:XHTML 元素必須被正確地嵌套。XHTML 元素必須被...
摘要:綜上所述有原型鏈繼承,構造函數繼承經典繼承,組合繼承,寄生繼承,寄生組合繼承五種方法,寄生組合式繼承,集寄生式繼承和組合繼承的優點于一身是實現基于類型繼承的最有效方法。 一、前言 繼承是面向對象(OOP)語言中的一個最為人津津樂道的概念。許多面對對象(OOP)語言都支持兩種繼承方式::接口繼承 和 實現繼承 。 接口繼承只繼承方法簽名,而實現繼承則繼承實際的方法。由于js中方法沒有簽名...
摘要:創建自定義的構造函數之后,其原型對象只會取得屬性,其他方法都是從繼承來的。優缺點寄生式繼承在主要考慮對象而不是創建自定義類型和構造函數時,是十分有用的。 原文鏈接:https://kongchenglc.coding.me... 1.原型鏈 ??js的繼承機制不同于傳統的面向對象語言,采用原型鏈實現繼承,基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。理解原型鏈必須先理...
閱讀 3434·2021-11-08 13:20
閱讀 3359·2021-09-30 09:48
閱讀 2560·2021-09-29 09:41
閱讀 589·2021-09-22 15:04
閱讀 2458·2021-08-23 09:44
閱讀 3663·2020-12-03 17:26
閱讀 1007·2019-08-30 14:10
閱讀 1561·2019-08-29 18:34