深入浅出理解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()判断对象是否具有某个非继承属性

猜你喜欢

转载自blog.csdn.net/m0_37782372/article/details/82223965