JS繼承的一些見解

2021-09-29 02:56:25 字數 4264 閱讀 1817

js在es6之前的繼承是五花八門的。而且要在專案中靈活運用物件導向寫法也是有點彆扭,更多的時候還是覺得面向過程的寫法更為簡單,效率也高。久而久之對js的繼承每隔一段時間就會理解出現困難。所以這次我要把對物件的理解寫下來,這樣應該就深刻一點了。

我們先來看看乙個物件是怎麼生成的

// 三種建立物件的方法

var obj = {}

var obj2 = new object()

var obj3 = object.create(null)

// 建立乙個空字串物件

var obj4 = new string()

obj.constructor === obj2.constructor // true

obj.__proto__ === obj2.__proto__ === object.prototype // true

obj4.__proto__ === string.prototype // true

obj4.__proto__.__proto__ === object.prototype // ture

這三種方法,前面兩種是一樣的。它們建立的空物件都具有原型,而第三種方式建立的是乙個真正意義上的空物件,它不繼承任何屬性;而obj4呢是乙個字串物件。看下圖的對比:

下面物件除了obj3都有個__proto__的隱性屬性,這個屬性指向的是該建立該例項的建構函式的原型。

這裡obj和obj2雖然是空物件,不過它們具有object建構函式的屬性的方法,而obj4除了有obj擁有的屬性和方法,它還具備了string擁有的屬性和方法;而obj3是真正的空物件,它的__proto__指向的是null。

我們再將obj4全部展開看看:

再來看看它們之間的關係:

如上圖,我舉得例子是object和string這兩個原生具有的構造器。它們的關係和我們平時寫的父類和子類之間的關係是一樣的,所有的類最終都會指向object。

在es5的時代,我們用到的繼承最簡單的就是原型鏈繼承了

// 我們先建立乙個父類

function super (name)

super.prototype.move = function ()

// 子類繼承父類

function child (name)

child.prototype = new super()

// 原型鏈繼承,子類原型的私有方法和屬性要在繼承之後新增,不然會被覆蓋

child.prototype.constructor = child // 修復對建構函式的指向

child.prototype.eat = function ()

原型鏈繼承就是將子類的原型等於父類的例項,然後再新增子類原型的屬性和方法。這樣的缺點就是只能繼承乙個父類。而且在建立子類的例項的時候,不能傳參給父類。在做單一繼承而且父類不需要傳參的時候,這種寫法是最好的選擇了。

下面在介紹一種我個人覺得已經很不錯的繼承方式(組合繼承)

// 子類繼承父類

function child (name)

child.prototype = new super()

child.prototype.constructor = child // 修復對建構函式的指向

child.prototype.eat = function ()

一般來說這種繼承方式已經很好了,**量少。繼承性好,弊端也沒有影響。這就是es6之前的繼承。下面再來看看es6是怎麼操作的。

上面這兩句話是引用阮一峰對es6的class的簡介(class 的基本語法)。阮大神的ecmascript 6 入門真的是對es6初學者居家必備的好東西。我在這裡就談談我的理解好了。

// 寫乙個class

class point

tostring()

}var point = new point(2, 3) // new乙個例項

下面看下point內部是怎樣的,可以看出constructor,tostring都是在「proto」內的。

在這裡會等價於建構函式的什麼寫法呢

// 寫乙個class

function point (x, y)

point.prototype.tostring = function ()

var point = new point(2, 3) // new乙個例項

在不考慮class靜態屬性的情況下,可以簡單理解為constructor內this下的新屬性和方法都屬於建構函式內的,而constructor外的方法都是prototype下的。

class childpoint extends point 

tostring ()

changex (x)

}var childpoint = new childpoint(2, 3, 4) // new乙個childpoint的例項

console.log(childpoint.x) // 2

console.log(childpoint.y) // 3

console.log(childpoint.z) // 4

console.log(childpoint.tostring()) // 2,3,4

childpoint.changex(5)

console.log(childpoint.x) // 5

console.log(childpoint.__proto__ === childpoint.prototype) // true

console.log(childpoint.__proto__.__proto__ === point.prototype) // true

console.log(childpoint.constructor === childpoint) // true

這裡class是通過extends繼承父類的,而子類的constructor方法內需要呼叫super()方法,這相當與呼叫了父類的constructor()方法。

下面看下childpoint的內部情況:

從和上面列印的情況可以看出,es6的繼承和組合繼承很是相似。唯一的不同點就是es6的繼承沒有組合繼承產生的多餘的乙份例項屬性在原型裡。看起來很順眼。不過相對的es6的不能多繼承(雖然組合繼承只能多繼承多個建構函式,並不能繼承多個原型)。

其實組合繼承還可以進一步公升級成es6繼承那個樣子的(寄生組合繼承):

// 我們先建立乙個父類

function super (name)

super.prototype.move = function ()

// 子類繼承父類

function child (name)

(function()

middlesuper.prototype = super.prototyoe // 跟super共享原型

// 在這裡middlesuper和super的區別就是有沒有例項了。

// 然後在正常進行組合繼承的操作

child.prototype = new middlesuper()

})()

child.prototype.constructor = child // 修復對建構函式的指向

child.prototype.eat = function ()

經過這一系列複雜的操作後我們就得到了乙份和es6一樣的結構了。不過es6只需要乙個extends,而es6之前我們就得長篇大論的寫才能實現,而且還特別繞。所以一句話,快去學es6吧。

更多專業前端知識,請上

【猿2048】www.mk2048.com

JS繼承的一些見解

js在es6之前的繼承是五花八門的。而且要在專案中靈活運用物件導向寫法也是有點彆扭,更多的時候還是覺得面向過程的寫法更為簡單,效率也高。久而久之對js的繼承每隔一段時間就會理解出現困難。所以這次我要把對物件的理解寫下來,這樣應該就深刻一點了。我們先來看看乙個物件是怎麼生成的 三種建立物件的方法 va...

個人對JS的一些見解

優點 1.廣泛,無論對於使用者還是開發者,可以說是最廣泛使用的程式語言 2.生態完美,多個端 多類庫 多種框架,眾多優秀團隊支援,迄今沒有任何一種語言能做到,真正的眾星拱月 3.能處理任何形式資料,特別是對於json的處理 4.易用,對初學相當友好,你只需要裝乙個瀏覽器,就能進行開發 5.特別適合於...

CSRF XSS Cookies 的一些見解

csrf 攻擊 在瀏覽器中插入了 惡意鏈結 並在使用者訪問之時讓使用者訪問,達到使用使用者的cooikes達到連線指定伺服器客戶的的驗證資訊,並進行一些簡單的操作。比如 防禦 最簡單的,可以通過驗證cookies進行一些防禦。例如在使用者操作驗證中,判斷是否又cookies傳過來,如果沒有則是惡意鏈...