亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JS高級ES6的6種繼承方式

 更新時間:2021年12月02日 09:57:59   作者:一碗周  
這篇文章主要和大家分享的事JS高級ES6的6種繼承方式,繼承是面向對象中老生常談的一個內容,在ECMAScript6之前,JavaScript中的繼承可謂是非常的繁瑣的,有各種各樣的繼承,本質上所有的繼承都是離不開原型鏈的,更多詳細內容請感興趣的小伙伴參考下面文章內容吧

前言:

繼承是面向對象中老生常談的一個內容,在ECMAScript6之前,JavaScript中的繼承可謂是非常的繁瑣的,有各種各樣的繼承,本質上所有的繼承都是離不開原型鏈的,ES6新增的extends關鍵字也是通過原型鏈實現(xiàn)的繼承,但是語法相對來說就簡單了很多。

關于原型鏈的內容,可以參考上篇文章兩張圖搞懂原型鏈

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

1.原型鏈繼承

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

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

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

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

// 將子類進行實例化
var child = new ChildClass()

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

上面的代碼圖解如下:

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

這種方式實現(xiàn)繼承有一個缺點就是多個實例會導致原型對象上的內容時共享的,內容之間會互相影響,測試代碼如下:

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' ]

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

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

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

示例代碼如下所示:

function Parent() {
  // 父級對象

  this.parent = 'parent'
}

Parent.prototype.name = '一碗周' // 為 Parent 父級對象的原型增加屬性

function Child() {
  // 子級對象

  this.child = 'child'

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

const child = new Child()

console.log(child)

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

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

使用這種方式的優(yōu)點是避免了引用類型的實例被所有對象共享,缺點是因為所有的方法都定義在了構造函數(shù)中,是不會繼承原型對象,而且每實例化一個對象之后都會重新創(chuàng)建一遍這些方法,占用內存空間,更別說函數(shù)復用了。

3.組合式繼承

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

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

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

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

示例代碼如下所示:

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

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

4.原型式繼承

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

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

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

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

該方式的缺點與第一種一樣,都是多個實例會導致原型對象上的內容時共享的,內容之間會互相影響。

5.寄生式繼承

寄生式繼承的基礎是在原型式繼承的的基礎上,增強對象,返回構造函數(shù),實例代碼如下:

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

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

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

它的缺點與原生式繼承是一樣的。

6.寄生組合式繼承

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

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

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

// 借用構造函數(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' ]

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

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

上圖中就是我們的核心代碼,然后我們來看一下默認的ParentClassChildClass的原型鏈是什么樣子的,

圖如下:

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

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

結語:

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

但是ECMAScript6新增的類本質上就是語法糖,只要是JavaScript談論繼承,始終離不開class關鍵字。

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

相關文章

最新評論