av一区二区在线观看_亚洲男人的天堂网站_日韩亚洲视频_在线成人免费_欧美日韩精品免费观看视频_久草视

您的位置:首頁技術文章
文章詳情頁

JavaScript六種繼承方式

瀏覽:10日期:2023-11-13 14:58:36

繼承是面向對象編程中又一非常重要的概念,JavaScript支持實現繼承,不支持接口繼承,實現繼承主要依靠原型鏈來實現的

原型鏈

首先得要明白什么是原型鏈,在 一篇文章看懂 proto 和prototype的關系及區別 中講得非常詳細

原型鏈繼承基本思想就是讓一個原型對象指向另一個類型的實例

function SuperType(){ this.property = true}SuperType.prototype.getSuperValue = function(){ return this.property}function SubType(){ this.subproperty = false}SubType.prototype = new SuperType()SubType.prototype.getSubValue = function(){ return this.subproperty}var instance = new SubType()console.log(instance.getSuperValue()) // true

代碼定義了兩個類型SuperType和SubType,每個類型分別有一個屬性和一個方法,SubType繼承了SuperType,而繼承是通過創建SuperType的實例,并將該實例賦給SubType.prototype實現的

實現的本質是重寫原型對象,代之以一個新類型的實例,那么存在SuperType的實例中的所有屬性和方法,現在也存在于SubType.prototype中了

我們知道,在創建一個實例的時候,實例對象中會有一個內部指針指向創建它的原型,進行關聯起來,在這里代碼 SubType.prototype = new SuperType() ,也會在SubType.prototype創建一個內部指針,將SubType.prototype與SuperType關聯起來

所以instance指向SubType的原型,SubType的原型又指向SuperType的原型,繼而在instance在調用getSuperValue()方法的時候,會順著這條鏈一直往上找

添加方法

在給SubType原型添加方法的時候,如果,父類上也有同樣的名字,SubType將會覆蓋這個方法,達到重新的目的。 但是這個方法依然存在于父類中

記住不能以字面量的形式添加,因為,上面說過通過實例繼承本質上就是重寫,再使用字面量形式,又是一次重寫了,但這次重寫沒有跟父類有任何關聯,所以就會導致原型鏈截斷

function SuperType(){ this.property = true}SuperType.prototype.getSuperValue = function(){ return this.property}function SubType(){ this.subproperty = false}SubType.prototype = new SuperType()SubType.prototype = { getSubValue:function(){ return this.subproperty }}var instance = new SubType()console.log(instance.getSuperValue()) // error

問題

單純的使用原型鏈繼承,主要問題來自包含引用類型值的原型。

function SuperType(){ this.colors = [’red’, ’blue’, ’green’]}function SubType(){}SubType.prototype = new SuperType()var instance1 = new SubType()var instance2 = new SubType()instance1.colors.push(’black’)console.log(instance1.colors) // ['red', 'blue', 'green', 'black']console.log(instance2.colors) // ['red', 'blue', 'green', 'black']

在SuperType構造函數定義了一個colors屬性,當SubType通過原型鏈繼承后,這個屬性就會出現SubType.prototype中,就跟專門創建了SubType.prototype.colors一樣,所以會導致SubType的所有實例都會共享這個屬性,所以instance1修改colors這個引用類型值,也會反映到instance2中

借用構造函數

此方法為了解決原型中包含引用類型值所帶來的問題

這種方法的思想就是在子類構造函數的內部調用父類構造函數,可以借助apply()和call()方法來改變對象的執行上下文

function SuperType(){ this.colors = [’red’, ’blue’, ’green’]}function SubType(){ // 繼承SuperType SuperType.call(this)}var instance1 = new SubType()var instance2 = new SubType()instance1.colors.push(’black’)console.log(instance1.colors) // ['red', 'blue', 'green', 'black']console.log(instance2.colors) // ['red', 'blue', 'green']

在新建SubType實例是調用了SuperType構造函數,這樣以來,就會在新SubType對象上執行SuperType函數中定義的所有對象初始化代碼

結果,SubType的每個實例就會具有自己的colors屬性的副本了

傳遞參數

借助構造函數還有一個優勢就是可以傳遞參數

function SuperType(name){ this.name = name}function SubType(){ // 繼承SuperType SuperType.call(this, ’Jiang’) this.job = ’student’}var instance = new SubType()console.log(instance.name) // Jiangconsole.log(instance.job) // student

問題

如果僅僅借助構造函數,方法都在構造函數中定義,因此函數無法達到復用

組合繼承(原型鏈+構造函數)

組合繼承是將原型鏈繼承和構造函數結合起來,從而發揮二者之長的一種模式

思路就是使用原型鏈實現對原型屬性和方法的繼承,而通過借用構造函數來實現對實例屬性的繼承

這樣,既通過在原型上定義方法實現了函數復用,又能夠保證每個實例都有它自己的屬性

function SuperType(name){ this.name = name this.colors = [’red’, ’blue’, ’green’]}SuperType.prototype.sayName = function(){ console.log(this.name)}function SubType(name, job){ // 繼承屬性 SuperType.call(this, name) this.job = job}// 繼承方法SubType.prototype = new SuperType()SubType.prototype.constructor = SuperTypeSubType.prototype.sayJob = function(){ console.log(this.job)}var instance1 = new SubType(’Jiang’, ’student’)instance1.colors.push(’black’)console.log(instance1.colors) //['red', 'blue', 'green', 'black']instance1.sayName() // ’Jiang’instance1.sayJob() // ’student’var instance2 = new SubType(’J’, ’doctor’)console.log(instance2.colors) // //['red', 'blue', 'green']instance2.sayName() // ’J’instance2.sayJob() // ’doctor’

這種模式避免了原型鏈和構造函數繼承的缺陷,融合了他們的優點,是最常用的一種繼承模式

原型式繼承

借助原型可以基于已有的對象創建新對象,同時還不必因此創建自定義類型

function object(o){ function F(){} F.prototype = o return new F()}

在object函數內部,先創建一個臨時性的構造函數,然后將傳入的對象作為這個構造函數的原型,最后返回這個臨時類型的一個新實例

本質上來說,object對傳入其中的對象執行了一次淺復制

var person = { name: ’Jiang’, friends: [’Shelby’, ’Court’]}var anotherPerson = object(person)console.log(anotherPerson.friends) // [’Shelby’, ’Court’]

這種模式要去你必須有一個對象作為另一個對象的基礎

在這個例子中,person作為另一個對象的基礎,把person傳入object中,該函數就會返回一個新的對象

這個新對象將person作為原型,所以它的原型中就包含一個基本類型和一個引用類型

所以意味著如果還有另外一個對象關聯了person,anotherPerson修改數組friends的時候,也會體現在這個對象中

Object.create()方法

ES5通過Object.create()方法規范了原型式繼承,可以接受兩個參數,一個是用作新對象原型的對象和一個可選的為新對象定義額外屬性的對象,行為相同,基本用法和上面的object一樣,除了object不能接受第二個參數以外

var person = { name: ’Jiang’, friends: [’Shelby’, ’Court’]}var anotherPerson = Object.create(person)console.log(anotherPerson.friends) // [’Shelby’, ’Court’] 寄生式繼承

寄生式繼承的思路與寄生構造函數和工廠模式類似,即創建一個僅用于封裝繼承過程的函數

function createAnother(o){ var clone = Object.create(o) // 創建一個新對象 clone.sayHi = function(){ // 添加方法 console.log(’hi’) } return clone // 返回這個對象}var person = { name: ’Jiang’}var anotherPeson = createAnother(person)anotherPeson.sayHi()

基于person返回了一個新對象anotherPeson,新對象不僅擁有了person的屬性和方法,還有自己的sayHi方法

在主要考慮對象而不是自定義類型和構造函數的情況下,這是一個有用的模式

寄生組合式繼承

在前面說的組合模式(原型鏈+構造函數)中,繼承的時候需要調用兩次父類構造函數

父類

function SuperType(name){ this.name = name this.colors = [’red’, ’blue’, ’green’]}

第一次在子類構造函數中

function SubType(name, job){ // 繼承屬性 SuperType.call(this, name) this.job = job}

第二次將子類的原型指向父類的實例

// 繼承方法SubType.prototype = new SuperType()

當使用 var instance = new SubType() 的時候,會產生兩組name和color屬性,一組在SubType實例上,一組在SubType原型上,只不過實例上的屏蔽了原型上的

使用寄生式組合模式,可以規避這個問題

這種模式通過借用構造函數來繼承屬性,通過原型鏈的混成形式來繼承方法

基本思路:不必為了指定子類型的原型而調用父類的構造函數,我們需要的無非就是父類原型的一個副本

本質上就是使用寄生式繼承來繼承父類的原型,在將結果指定給子類型的原型

function inheritPrototype(subType, superType){ var prototype = Object.create(superType.prototype) prototype.constructor = subType subType.prototype = prototype}

該函數實現了寄生組合繼承的最簡單形式

這個函數接受兩個參數,一個子類,一個父類

第一步創建父類原型的副本,第二步將創建的副本添加constructor屬性,第三部將子類的原型指向這個副本

function SuperType(name){ this.name = name this.colors = [’red’, ’blue’, ’green’]}SuperType.prototype.sayName = function(){ console.log(this.name)}function SubType(name, job){ // 繼承屬性 SuperType.call(this, name) this.job = job}// 繼承inheritPrototype(SubType, SuperType)var instance = new SubType(’Jiang’, ’student’)instance.sayName()

補充:直接使用Object.create來實現,其實就是將上面封裝的函數拆開,這樣演示可以更容易理解

function SuperType(name){ this.name = name this.colors = [’red’, ’blue’, ’green’]}SuperType.prototype.sayName = function(){ console.log(this.name)}function SubType(name, job){ // 繼承屬性 SuperType.call(this, name) this.job = job}// 繼承SubType.prototype = Object.create(SuperType.prototype)// 修復constructorSubType.prototype.constructor = SubTypevar instance = new SubType(’Jiang’, ’student’)instance.sayName()

ES6新增了一個方法, Object.setPrototypeOf ,可以直接創建關聯,而且不用手動添加constructor屬性

// 繼承Object.setPrototypeOf(SubType.prototype, SuperType.prototype)console.log(SubType.prototype.constructor === SubType) // true

來自:https://xxxgitone.github.io/2017/06/12/JavaScript六種繼承方式/

標簽: JavaScript
相關文章:
主站蜘蛛池模板: 免费看a | 激情久久网| 精品二三区 | 激情一区 | 亚洲成人精品在线 | 欧美在线观看免费观看视频 | 高清国产午夜精品久久久久久 | 夜夜爽99久久国产综合精品女不卡 | 久久99精品久久久久久国产越南 | 国产69精品久久99不卡免费版 | 久久久夜 | 中文字幕在线观看视频一区 | 日韩成人精品 | 91看片网 | jlzzjlzz国产精品久久 | 国产福利在线视频 | 婷婷福利 | 小川阿佐美pgd-606在线 | 国产精品一区二区电影 | 欧美成人自拍 | 深夜福利影院 | 99精品国产一区二区青青牛奶 | 中午字幕在线观看 | 久久久精品一区 | 国产精品大片在线观看 | 国产aaaaav久久久一区二区 | 国产一区三区在线 | 成人一区二 | 国产精品久久久久久久久久久久久 | 午夜天堂精品久久久久 | 亚洲欧美视频在线观看 | 天天av天天好逼 | 亚洲欧美日韩系列 | 中文字幕免费在线 | 一区精品视频在线观看 | 亚洲精品91 | 电影91久久久 | av毛片| 午夜爱爱毛片xxxx视频免费看 | 粉嫩粉嫩芽的虎白女18在线视频 | www.4hu影院 |