成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

JS 常見的 六種繼承方式,你知道幾種?

開發 前端
構造函數實現繼承的優缺點,它使父類的引用屬性不會被共享,優化了第一種繼承方式的弊端;但是隨之而來的缺點也比較明顯——只能繼承父類的實例屬性和方法,不能繼承原型屬性或者方法。

原型鏈繼承

原型鏈繼承是比較常見的繼承方式之一,其中涉及的構造函數、原型和實例,三者之間存在著一定的關系,即每一個構造函數都有一個原型對象,原型對象又包含一個指向構造函數的指針,而實例則包含一個原型對象的指針。例如:

function Parent1() {
    this.name = 'parent1';
    this.play = [1, 2, 3]
}
function Child1() {
    this.type = 'child2';
}
Child1.prototype = new Parent1();
console.log(new Child1());

上面的代碼其實有一個潛在的問題,例如:

var s1 = new Child1();
var s2 = new Child1();
s1.play.push(4);
console.log(s1.play);
console.log(s2.play);

執行結果如下:

當我修改了s1的play屬性的時候,s2的play屬性也跟著變了,因為兩個實例使用的是同一個原型對象。它們的內存空間是共享的,當一個發生變化的時候,另外一個也隨之進行了變化,這就是使用原型鏈繼承方式的一個缺點。

構造函數繼承(借助 call)

function Parent1(){
    this.name = 'parent1';
}

Parent1.prototype.getName = function () {
    return this.name;
}

function Child1(){
    Parent1.call(this);
    this.type = 'child1'
}

let child = new Child1();
console.log(child);  // 沒問題
console.log(child.getName());  // 會報錯
-----------------------------------
?著作權歸作者所有:來自51CTO博客作者前端面試題庫助手的原創作品,請聯系作者獲取轉載授權,否則將追究法律責任
JS 常見的 6 種繼承方式
https://blog.51cto.com/u_14627797/8080448

運行結果如下:

除了 Child1 的屬性 type 之外,也繼承了 Parent1 的屬性 name。這樣寫的時候子類雖然能夠拿到父類的屬性值,解決了第一種繼承方式的弊端,但問題是,父類原型對象中一旦存在父類之前自己定義的方法,那么子類將無法繼承這些方法。

因此構造函數實現繼承的優缺點,它使父類的引用屬性不會被共享,優化了第一種繼承方式的弊端;但是隨之而來的缺點也比較明顯——只能繼承父類的實例屬性和方法,不能繼承原型屬性或者方法。

組合繼承(前兩種組合)

這種方式結合了前兩種繼承方式的優缺點,結合起來的繼承,代碼如下:

function Parent3 () {
    this.name = 'parent3';
    this.play = [1, 2, 3];
  }
  Parent3.prototype.getName = function () {
    return this.name;
  }
  function Child3() {
    // 第二次調用 Parent3()
    Parent3.call(this);
    this.type = 'child3';
  }

  // 第一次調用 Parent3()
  Child3.prototype = new Parent3();
  // 手動掛上構造器,指向自己的構造函數
  Child3.prototype.constructor = Child3;
  var s3 = new Child3();
  var s4 = new Child3();
  s3.play.push(4);
  console.log(s3.play);  // 不互相影響
  console.log(s4.play);
  console.log(s3.getName()); // 正常輸出'parent3'
  console.log(s4.getName()); // 正常輸出'parent3'

結果如下:

之前方法一和方法二的問題都得以解決,但是這里又增加了一個新問題:通過注釋我們可以看到 Parent3 執行了兩次,第一次是改變Child3 的 prototype 的時候,第二次是通過 call 方法調用 Parent3 的時候,那么 Parent3 多構造一次就多進行了一次性能開銷。

原型式繼承

ES5 里面的 Object.create 方法,這個方法接收兩個參數:一是用作新對象原型的對象、二是為新對象定義額外屬性的對象(可選參數)。


let parent4 = {
    name: "parent4",
    friends: ["p1", "p2", "p3"],
    getName: function() {
        return this.name;
    }
};

let person4 = Object.create(parent4);
person4.name = "tom";
person4.friends.push("jerry");

let person5 = Object.create(parent4);
person5.friends.push("lucy");

console.log(person4.name);
console.log(person4.name === person4.getName());
console.log(person5.name);
console.log(person4.friends);
console.log(person5.friends);

執行結果如下:

通過 Object.create 這個方法可以實現普通對象的繼承,不僅僅能繼承屬性,同樣也可以繼承 getName 的方法。前三個輸出都是正常的,最后兩個輸出結果一致是因為Object.create 方法是可以為一些對象實現淺拷貝的,那么關于這種繼承方式的缺點也很明顯,多個實例的引用類型屬性指向相同的內存。

寄生式繼承

使用原型式繼承可以獲得一份目標對象的淺拷貝,然后利用這個淺拷貝的能力再進行增強,添加一些方法,這樣的繼承方式就叫作寄生式繼承。

雖然其優缺點和原型式繼承一樣,但是對于普通對象的繼承方式來說,寄生式繼承相比于原型式繼承,還是在父類基礎上添加了更多的方法。實現如下:

let parent5 = {
    name: "parent5",
    friends: ["p1", "p2", "p3"],
    getName: function() {
        return this.name;
    }
};

function clone(original) {
    let clone = Object.create(original);
    clone.getFriends = function() {
        return this.friends;
    };
    return clone;
}

let person5 = clone(parent5);

console.log(person5.getName());
console.log(person5.getFriends());

輸出結果如下:

從最后的輸出結果中可以看到,person5 通過 clone 的方法,增加了 getFriends 的方法,從而使 person5 這個普通對象在繼承過程中又增加了一個方法,這樣的繼承方式就是寄生式繼承。

寄生組合式繼承

結合第四種中提及的繼承方式,解決普通對象的繼承問題的 Object.create 方法,我們在前面這幾種繼承方式的優缺點基礎上進行改造,得出了寄生組合式的繼承方式,這也是所有繼承方式里面相對最優的繼承方式,代碼如下:

function clone (parent, child) {
    // 這里改用 Object.create 就可以減少組合繼承中多進行一次構造的過程
    child.prototype = Object.create(parent.prototype);
    child.prototype.constructor = child;
}

function Parent6() {
    this.name = 'parent6';
    this.play = [1, 2, 3];
}
Parent6.prototype.getName = function () {
    return this.name;
}
function Child6() {
    Parent6.call(this);
    this.friends = 'child5';
}

clone(Parent6, Child6);
    Child6.prototype.getFriends = function () {
    return this.friends;
}

let person6 = new Child6();
console.log(person6);
console.log(person6.getName());
console.log(person6.getFriends());
-----------------------------------
?著作權歸作者所有:來自51CTO博客作者前端面試題庫助手的原創作品,請聯系作者獲取轉載授權,否則將追究法律責任
JS 常見的 6 種繼承方式
https://blog.51cto.com/u_14627797/8080448

執行結果如下:

這種寄生組合式繼承方式,基本可以解決前幾種繼承方式的缺點,較好地實現了繼承想要的結果,同時也減少了構造次數,減少了性能的開銷。整體看下來,這六種繼承方式中,寄生組合式繼承是這六種里面最優的繼承方式。

ES6的extends關鍵字實現邏輯

ES6提供了extends語法糖,使用關鍵字很容易實現JavaScript的繼承,先看一下extends使用方法。

class Person {
  constructor(name) {
    this.name = name
  }
  // 原型方法
  // 即 Person.prototype.getName = function() { }
  // 下面可以簡寫為 getName() {...}
  getName = function () {
    console.log('Person:', this.name)
  }
}
class Gamer extends Person {
  constructor(name, age) {
    // 子類中存在構造函數,則需要在使用“this”之前首先調用 super()。
    super(name)
    this.age = age
  }
}
const asuna = new Gamer('Asuna', 20)
asuna.getName() // 成功訪問到父類的方法

使用babel將ES6 的代碼編譯成 ES5,代碼如下:

function _possibleConstructorReturn (self, call) { 
		// ...
		return call && (typeof call === 'object' || typeof call === 'function') ? call : self; 
}
function _inherits (subClass, superClass) { 
    // 這里可以看到
	subClass.prototype = Object.create(superClass && superClass.prototype, { 
		constructor: { 
			value: subClass, 
			enumerable: false, 
			writable: true, 
			configurable: true 
		} 
	}); 
	if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; 
}

var Parent = function Parent () {
	// 驗證是否是 Parent 構造出來的 this
	_classCallCheck(this, Parent);
};
var Child = (function (_Parent) {
	_inherits(Child, _Parent);
	function Child () {
		_classCallCheck(this, Child);
		return _possibleConstructorReturn(this, (Child.__proto__ || Object.getPrototypeOf(Child)).apply(this, arguments));
}
	return Child;
}(Parent));
責任編輯:武曉燕 來源: 51CTO博客
相關推薦

2025-01-21 10:04:40

Java并發阻塞隊列

2021-12-15 23:10:34

JS Debugger 前端開發

2019-09-02 11:14:08

隔離虛擬機操作系統

2017-06-26 10:35:58

前端JavaScript繼承方式

2025-04-17 07:10:03

API架構項目

2022-03-28 20:57:31

私有屬性class屬性和方法

2021-01-08 10:52:22

物聯網萬物互聯IoT,Interne

2018-08-03 16:40:06

前端前端框架微服務

2018-07-04 11:02:23

無線傳輸模式

2023-11-28 15:32:30

負載均衡算法

2025-02-27 00:00:30

SpringJava方式

2019-05-16 13:00:18

異步編程JavaScript回調函數

2009-02-11 09:46:00

ASON網絡演進

2024-11-11 06:20:00

緩存開發

2020-12-15 10:54:22

物聯網互聯網IoT

2020-10-27 10:33:01

物聯網

2021-05-07 16:19:36

異步編程Java線程

2019-01-17 10:58:52

JS異步編程前端

2022-03-23 12:55:50

農業物聯網

2017-07-20 08:47:19

網頁加載時間移動開發IT
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日日日视频 | 成人性生交a做片 | 成人一区二区视频 | 九九热这里 | 四虎影院免费在线 | 成人一区精品 | 色男人的天堂 | 插插插干干干 | 亚洲精品在线看 | 欧美一页 | 999国产视频 | 久久精品视频在线播放 | 久久精品日产第一区二区三区 | 黄篇网址 | 在线欧美一区二区 | 亚洲精品欧美一区二区三区 | 国产精品1区 | 欧美一区 | 日韩一区二区在线观看视频 | 国产91九色 | 天堂一区二区三区 | 精品欧美乱码久久久久久 | 99re视频精品 | 日韩国产一区 | 欧美a免费 | 亚洲欧洲精品在线 | 欧美精品三区 | 国产美女特级嫩嫩嫩bbb片 | 国产91黄色 | 一区二区高清不卡 | 国产精品国产成人国产三级 | 亚洲综合视频一区 | 罗宾被扒开腿做同人网站 | 欧美日韩在线观看一区 | 精品久久久久久亚洲国产800 | 日韩电影免费在线观看中文字幕 | 国产精品毛片久久久久久 | 中文精品一区二区 | 欧美中文 | 久久精品视频91 | 免费成人高清 |