實現繼承的幾種方式

2022-06-30 01:48:09 字數 3691 閱讀 2807

要搞懂js繼承,我們首先要理解原型鏈:每乙個例項物件都有乙個__proto__屬性(隱式原型),在js內部用來查詢原型鏈;每乙個建構函式都有prototype屬性(顯式原型),用來顯示修改物件的原型,例項.__proto__=建構函式.prototype=原型。原型鏈的特點就是:通過例項.__proto__查詢原型上的屬性,從子類一直向上查詢物件原型的屬性,繼而形成乙個查詢鏈即原型鏈。

我們使用原型繼承時,主要利用sub.prototype=new super,這樣連通了子類-子類原型-父類。

核心:將父類的例項作為子類的原型。

//父類,帶屬性  

function super()

//為了提高復用性,方法繫結在父類原型屬性上

super.prototype.getflag = function()

//來個子類

function sub()

//實現繼承

sub.prototype = new super();

//給子類新增子類特有的方法,注意順序要在繼承之後

sub.prototype.getsubflag = function()

//構造例項

var es5 = new sub;

特點:

1. 非常純粹的繼承關係,例項是子類的例項,也是父類的例項

2. 父類新增原型方法/原型屬性,子類都能訪問到

為啥不用a.prototype = b.prototype的方式呢

因為如果更改a.prototype的話,會更改b.protptype 就是汙染了b.prototype,就不能稱之為繼承。

而通過a.prototype = new b();如果更改a.prototype的話,不更改b.prototype,安全有效

缺點:來自原型物件的引用屬性是所有例項共享的,即屬性沒有私有化,原型物件上屬性的改變(即 new super出來的物件)會作用到所有的例項上。

核心:使用父類的的建構函式來增強子類例項,等於是複製父類的例項屬性給子類(沒用到原型)

function super()  

function sub()

var obj = new sub();

obj.flag = flase;

var obj_2 = new sub();

console.log(obj_2.flag) //依然是true,不會相互影響

優缺點:實現了屬性的私有化,但是子類無法訪問父類原型上的屬性。

特點:1. 解決了1中,子類例項共享父類引用屬性的問題

2. 建立子類例項時,可以向父類傳遞引數

3. 可以實現多繼承(call多個父類物件)

缺點:1. 例項並不是父類的例項,只是子類的例項

2. 只能繼承父類的例項屬性和方法,不能繼承原型屬性/方法

無法實現函式復用,每個子類都有父類例項函式的副本,影響效能

利用建構函式和原型鏈的方法,可以比較完美的實現繼承

function super()  

super.prototype.getflag = function()

function sub()

sub.prototype = new super;

var obj = new sub();

// sub.prototype = new super; 會導致sub.prototype的constructor指向super;

// 然而constructor的定義是要指向原型屬性對應的建構函式的,sub.prototype是sub建構函式的原型,

// 所以應該新增一句糾正:sub.prototype.constructor = sub;

sub.prototype.constructor = sub; // 修復建構函式指向

super.prototype.getsubflag = function()

特點:

1. 彌補了方式2的缺陷,可以繼承例項屬性/方法,也可以繼承原型屬性/方法

2. 既是子類的例項,也是父類的例項

3. 不存在引用屬性共享問題

4. 可傳參

5. 函式可復用

缺點:1. 呼叫了兩次父類建構函式,生成了兩份例項(子類例項將子類原型上的那份遮蔽了)

核心:通過寄生方式,砍掉父類的例項屬性,這樣,在呼叫兩次父類的構造的時候,就不會初始化兩次例項方法/屬性,避免的組合繼承的缺點

function fu(name) 

}fu.prototype.sayhi = function()

function zi(name)

// object.create建立物件,第乙個引數指定原型物件

//這樣可以把父物件的原型繼承下來 而不會繼承父物件建構函式中的屬性和方法

在父物件.call(this)的時候才把建構函式中的屬性和方法拿到,這樣不會造成二次賦值

zi.prototype = object.create(fu.prototype);

zi.prototype.constructor = zi;

相當於下面的函式,先初始化乙個f建構函式,f的原型指向obj,返回f的建構函式

function create(obj) ;

f.prototype = obj;

return new f();

}

特點:使用到了object.create(fu.prototype)實現原型鏈的淺拷貝

優點:解決了原型鏈繼承和建構函式繼承的缺點

​ 缺點:

function fu(name) 

}fu.prototype.sayhi = function()

function zi(name)

// 在繼承之前定義的方法 是會不見的

zi.prototype.subsay = function()

zi.prototype = object.create(fu.prototype);

zi.prototype.constructor = zi;

思想:

另外加個建構函式 function f(){}當做中間層,然後讓 f 和 father 共有乙個原型 f.prototype=father.prototype,然後 son.prototype = new f();使用原型鏈形成了繼承關係,現在改 son.prototype 就不會影響 father.prototype

function inherit (function();

return function(target,origin)

})father.prototype.lastname = "alex";

function father()

function son()

inherit(son,father);

var son = new son();

var father new fahter();

注意:

(1)利用了閉包的機制 ,形成閉包,讓f 變成了私有化變數。畢竟f函式只是乙個過渡層,沒有其它的作用。生成閉包將其不暴露在外是最好的。

(2)聖杯模式繼承和寄生組合繼承都是較好的處理繼承的方法。

參考文章

js實現繼承的幾種方式

一,js中物件繼承 js中有三種繼承方式 1.js原型 prototype 實現繼承 複製 如下 2.建構函式實現繼承 複製 如下 複製 如下 js手冊中對call的解釋 複製 如下 call 方法 呼叫乙個物件的乙個方法,以另乙個物件替換當前物件。call thisobj arg1 arg2 ar...

JS實現繼承的幾種方式

取自 1.js實現繼承的幾種方式 2.js 物件導向之繼承 多種組合繼承 js作為物件導向的弱型別語言,繼承也是其非常強大的特性之一。那麼如何在js中實現繼承呢?讓我們拭目以待。既然要實現繼承,那麼首先我們得有乙個父類,如下 定義乙個動物類 function animal name 原型方法 ani...

javascript實現繼承的幾種方式

前言 js作為物件導向的弱型別語言,繼承也是其非常強大的特性之一。那麼如何在js中實現繼承呢?讓我們拭目以待。既然要實現繼承,那麼首先我們得有乙個父類,如下 定義乙個動物類 function animal name 原型方法 animal.prototype.eat function food 核心...