深入淺出理解JS原型鏈繼承
引出
js在ES6以前還沒有class的概念,但卻存在著面向物件的思想。在js中,可通過建構函式的形式來建立物件,並使用各種方式實現繼承,其中原型鏈繼承便是一種普遍的方法
什麼是原型鏈繼承
先來看一個例子
function Parent () { this.type = 'obj' } function Child () { this.name = 'zs', this.age = 13 } Child.prototype = new Parent() for(let i in obj) { console.log(i+':'+obj[i]) } // type: obj // name: zs // age: 13
程式碼中的Parent是一個建構函式,其中的this在new時會指向當前執行他的物件,也就是Parent的例項,Child這個建構函式通過prototype屬性指向一個原型物件,在這裡是new Parent(),也就是Parent的一個例項。以上就實現了原型鏈繼承,在這裡你可能會一臉茫然,接下來我會提出幾個問題並進行解釋。
為什麼說this在new時執行當前執行他的物件?
這裡首先引用網上的一句解釋:,this的指向在函式定義的時候是確定不了的,只有函式執行的時候才能確定this到底指向誰,實際上this的最終指向的是那個呼叫它的物件。
這裡更精確的說是指向上一級呼叫它的物件。
function Test () {
this.name = 'test'
console.log(this)
console.log(this.name)
}
Test()
//window
//test
console.log(window.name)
//test
var test = new Test()
//Test()
//test
js檔案的最外層有一個預設的window物件,建構函式Test通過Test()的方式執行,則this指向呼叫它的物件,也就是window(Test()等價於window.Test())。
當使用var test = new Test()的方式建立物件時,this指向呼叫它的物件,也就是test這個例項。
prototype是什麼,__proto__又是什麼?
prototype和__proto__都是指向原型物件的一個屬性。
prototype是建構函式的屬性,指向建構函式的原型物件;__proto__是例項物件的屬性,指向例項物件的原型物件。
這裡又衍生一個問題,什麼是原型物件?
原型物件是在建構函式建立同時建立的一個物件,它包含由它建立的所有例項的公共屬性和方法。
也就是說建構函式可以通過prototype獲取這個原型物件,並使用它的屬性和方法。
function Parent () {
this.type = 'parent'
}
function Child () {
this.name = 'zs',
this.age = 13
}
var parent = new Parent()
console.log(parent.__proto__)
console.log(Parent.prototype)
console.log(Parent.prototype.constructor)
Child.prototype = new Parent()
console.log(Child.prototype)
var obj = new Child()
console.log(obj.__proto__)
for(let i in obj) {
console.log(i+':'+obj[i])
}
Object.keys(obj).forEach(function(item,index) {
console.log(item + ':' + obj[item])
})
Object.getOwnPropertyNames(obj).forEach(function(item, index) {
console.log(item+ ':' + obj[item])
})
上面的Parent和Child是建構函式,在建立建構函式的同時建立了原型物件。
parent是Parent原型的一個例項,因此通過parent.__proto__和Parent.prototype可以訪問到它們的原型物件。
Child.prototype = new Parent()使Child這個建構函式的原型變為Parent的一個例項。
obj.__proto__也指向Child的原型物件。
使用 for...in遍歷物件的屬性,輸出obj原型鏈上的所有屬性
Object.keys()和Object.getOwnPropertyNames()不會輸出物件繼承來的屬性
也可以使用obj.hasOwnProperty()判斷物件是否具有某個非繼承屬性