欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS高級(jí)ES6的6種繼承方式

 更新時(shí)間:2021年12月02日 09:57:59   作者:一碗周  
這篇文章主要和大家分享的事JS高級(jí)ES6的6種繼承方式,繼承是面向?qū)ο笾欣仙U劦囊粋€(gè)內(nèi)容,在ECMAScript6之前,JavaScript中的繼承可謂是非常的繁瑣的,有各種各樣的繼承,本質(zhì)上所有的繼承都是離不開原型鏈的,更多詳細(xì)內(nèi)容請(qǐng)感興趣的小伙伴參考下面文章內(nèi)容吧

前言:

繼承是面向?qū)ο笾欣仙U劦囊粋€(gè)內(nèi)容,在ECMAScript6之前,JavaScript中的繼承可謂是非常的繁瑣的,有各種各樣的繼承,本質(zhì)上所有的繼承都是離不開原型鏈的,ES6新增的extends關(guān)鍵字也是通過原型鏈實(shí)現(xiàn)的繼承,但是語法相對(duì)來說就簡(jiǎn)單了很多。

關(guān)于原型鏈的內(nèi)容,可以參考上篇文章兩張圖搞懂原型鏈

本篇文章就來介紹一下在ECMAScript6之前是怎么實(shí)現(xiàn)繼承的。

1.原型鏈繼承

借助于原型鏈繼承本質(zhì)就是修改一下原型的指向即可,實(shí)現(xiàn)代碼如下:

function ParentClass() {
  this.name = '一碗周'
}
ParentClass.prototype.getName = function () {
  return this.name
}

// 定義子類,將來用于繼承父類
function ChildClass() {}

// * 將子類的原型指向父類的實(shí)例化,子類擁有父類實(shí)例化后的內(nèi)容
ChildClass.prototype = new ParentClass()

// 將子類進(jìn)行實(shí)例化
var child = new ChildClass()

console.log(child.getName()) // 一碗周

上面的代碼圖解如下:

圖中紅色線表示這個(gè)構(gòu)造函數(shù)與實(shí)例對(duì)象的原型鏈,通過這個(gè)原型鏈的關(guān)系,從而實(shí)現(xiàn)了繼承。

這種方式實(shí)現(xiàn)繼承有一個(gè)缺點(diǎn)就是多個(gè)實(shí)例會(huì)導(dǎo)致原型對(duì)象上的內(nèi)容時(shí)共享的,內(nèi)容之間會(huì)互相影響,測(cè)試代碼如下:

function ParentClass() {
  this.colors = ['red', 'blue', 'green']
}
function ChildClass() {}

ChildClass.prototype = new ParentClass()

var child1 = new ChildClass()
var child2 = new ChildClass()
console.log(child1.colors) // [ 'red', 'blue', 'green' ]

child2.colors.push('black')
console.log(child2.colors) // [ 'red', 'blue', 'green', 'black' ]

console.log(child1.colors) // [ 'red', 'blue', 'green', 'black' ]

測(cè)試代碼中的child1并沒有進(jìn)行修改,但是修改了child1之后,child1中的值也發(fā)生了改變。

2.借助構(gòu)造函數(shù)繼承

所謂的借助構(gòu)造函數(shù)繼承(有些資料也稱為偽造對(duì)象或經(jīng)典繼承),就是通過子對(duì)象借助Function.call()或者Function.apply()方法調(diào)用父類構(gòu)造函數(shù)完成繼承,

示例代碼如下所示:

function Parent() {
  // 父級(jí)對(duì)象

  this.parent = 'parent'
}

Parent.prototype.name = '一碗周' // 為 Parent 父級(jí)對(duì)象的原型增加屬性

function Child() {
  // 子級(jí)對(duì)象

  this.child = 'child'

  Parent.call(this) // 使用 call() 或者 apply() 方法調(diào)用父級(jí)構(gòu)造函數(shù) 實(shí)現(xiàn)繼承。
}

const child = new Child()

console.log(child)

console.log(child.name) // undefined     // 不會(huì)繼承父類的原型

執(zhí)行流程如下所示:

使用這種方式的優(yōu)點(diǎn)是避免了引用類型的實(shí)例被所有對(duì)象共享,缺點(diǎn)是因?yàn)樗械姆椒ǘ级x在了構(gòu)造函數(shù)中,是不會(huì)繼承原型對(duì)象,而且每實(shí)例化一個(gè)對(duì)象之后都會(huì)重新創(chuàng)建一遍這些方法,占用內(nèi)存空間,更別說函數(shù)復(fù)用了。

3.組合式繼承

之前掌握的兩種繼承方式都是存在缺點(diǎn)的,基于原型繼承的繼承方式,所有實(shí)例化后的對(duì)象都共享原型的方法和屬性,如果有一個(gè)更改則都會(huì)進(jìn)行更改。而借助構(gòu)造函數(shù)繼承的方式又無法繼承原型屬性。所以就出現(xiàn)了結(jié)合式繼承,就是將基于原型繼承方式和借助構(gòu)造函數(shù)的繼承方式結(jié)合起來,取其精華去其糟粕的一種繼承方式。

實(shí)現(xiàn)組合式繼承的基本思路如下:

  • 使用原型鏈或原型式繼承實(shí)現(xiàn)對(duì)原型的屬性和方法的繼承。
  • 通過結(jié)構(gòu)構(gòu)造函數(shù)實(shí)現(xiàn)對(duì)實(shí)例對(duì)象的屬性的繼承。

這樣,既通過在原型上定義方法實(shí)現(xiàn)了函數(shù)的復(fù)用,又可以保證每個(gè)對(duì)象都有自己的專有屬性。

示例代碼如下所示:

// 父級(jí)對(duì)象
function Parent() {
  this.parent = 'parent'
}
// 為 Parent 父級(jí)對(duì)象的原型增加屬性
Parent.prototype.name = '一碗周'
// 子級(jí)對(duì)象
function Child() {
  this.child = 'child'
  // 使用 call() 或者 apply() 方法調(diào)用父級(jí)構(gòu)造函數(shù) 實(shí)現(xiàn)繼承。
  Parent.call(this)
}
// 解決不會(huì)繼承構(gòu)造函數(shù)的原型對(duì)象的問題
Child.prototype = Parent.prototype

const child = new Child()
console.log(child.name) // 一碗周

4.原型式繼承

我們可以使用Object.create()方法實(shí)現(xiàn)一種繼承,實(shí)例代碼如下:

var person = {
  name: '一碗周',
  friends: ['張三', '李四', '王五'],
}

var anotherPerson = Object.create(person)
anotherPerson.name = '一碗甜'
anotherPerson.friends.push('趙六')

console.log(person.friends) // [ '張三', '李四', '王五', '趙六' ]

該方式的缺點(diǎn)與第一種一樣,都是多個(gè)實(shí)例會(huì)導(dǎo)致原型對(duì)象上的內(nèi)容時(shí)共享的,內(nèi)容之間會(huì)互相影響。

5.寄生式繼承

寄生式繼承的基礎(chǔ)是在原型式繼承的的基礎(chǔ)上,增強(qiáng)對(duì)象,返回構(gòu)造函數(shù),實(shí)例代碼如下:

var person = {
  name: '一碗周',
  friends: ['張三', '李四', '王五'],
}

function createAnother(original) {
  var clone = Object.create(original) // 通過調(diào)用 object() 函數(shù)創(chuàng)建一個(gè)新對(duì)象
  clone.sayMe = function () {
    // 以某種方式來增強(qiáng)對(duì)象
  }
  return clone // 返回這個(gè)對(duì)象
}

var anotherPerson = createAnother(person)
anotherPerson.sayMe()

它的缺點(diǎn)與原生式繼承是一樣的。

6.寄生組合式繼承

該繼承方式是借助構(gòu)造函數(shù)傳遞參數(shù)和寄生式繼承所實(shí)現(xiàn)的,實(shí)例代碼如下:

function inheritPrototype(ChildClass, ParentClass) {
  var prototype = Object.create(ParentClass.prototype) // 創(chuàng)建對(duì)象,創(chuàng)建父類原型的一個(gè)副本
  // 修改創(chuàng)建的父類原型副本的 constructor 并將子類的 prototype 指向這個(gè)類,形成與父類無關(guān)聯(lián)的類
  prototype.constructor = ChildClass
  ChildClass.prototype = prototype
}

// 父類初始化實(shí)例屬性和原型屬性
function ParentClass(name) {
  this.name = name
  this.colors = ['red', 'blue', 'green']
}
ParentClass.prototype.sayName = function () {
  console.log(this.name)
}

// 借用構(gòu)造函數(shù)傳遞增強(qiáng)子類實(shí)例屬性(支持傳參和避免篡改)
function ChildClass(name, age) {
  // 拷貝父類所有自有屬性
  ParentClass.call(this, name)
  this.age = age
}

// 將父類原型指向子類
inheritPrototype(ChildClass, ParentClass)

// 新增子類原型屬性
ChildClass.prototype.sayAge = function () {
  console.log(this.age)
}

var instance1 = new ChildClass('一碗周', 19)
var instance2 = new ChildClass('一碗甜', 18)

instance1.colors.push('black')
console.log(instance1.colors) // [ 'red', 'blue', 'green', 'black' ]
instance1.sayName() // 一碗周
instance2.colors.push('yellow')
console.log(instance2.colors) // [ 'red', 'blue', 'green', 'yellow' ]

這個(gè)例子的高效率體現(xiàn)在它只調(diào)用了一次ParentClass構(gòu)造函數(shù),并且因此避免了在ChildClass.prototype上創(chuàng)建不必要的、多余的屬性。于此同時(shí),原型鏈還能保持不變;因此,還能夠正常使用instanceofisPrototypeOf()。

如果你沒有看懂,那就繼續(xù)看,首先,我們將核心代碼進(jìn)行抽離,如下圖:

上圖中就是我們的核心代碼,然后我們來看一下默認(rèn)的ParentClassChildClass的原型鏈?zhǔn)鞘裁礃幼拥模?/p>

圖如下:

然后我們調(diào)用inheritPrototype()方法,并將修改ChildClass的原型,解析圖如下:

最后不要忘記了在子類中通過call()方法調(diào)用父類,從而實(shí)現(xiàn)copy父類的自有屬性,至此就實(shí)現(xiàn)了一個(gè)比較完善的繼承方式。

結(jié)語:

這篇文章介紹了除extends關(guān)鍵字之外的六種繼承方式,雖然說在ECMAScript6中新增了class關(guān)鍵字以及類相關(guān)的所有內(nèi)容,文本介紹的繼承方式都已經(jīng)不怎么使用了。

但是ECMAScript6新增的類本質(zhì)上就是語法糖,只要是JavaScript談?wù)摾^承,始終離不開class關(guān)鍵字。

到此這篇關(guān)于JS高級(jí)ES6的6種繼承方式的文章就介紹到這了,更多相關(guān)ES6的6種繼承方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論