1. 程式人生 > >深入淺出理解JS原型鏈繼承

深入淺出理解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()判斷物件是否具有某個非繼承屬性