在学习js原型与原型链之前,我们要搞懂new关键字的作用,这会有助于我们理解原型和原型链。
new关键字的作用:
1、在构造函数内初始化一个新的对象
2、将对象内的__proto__属性指向原型对象,确定该对象的原型链
3、将构造函数内的this指针指向这个新的对象
4、返回结果
注:本文章只讨论原型与原型链,构图上不写其他属性
一、什么是原型和原型对象:
每一个函数都有一个prototype属性,这个属性就是原型。该属性是一个指针,指向一个对象,这个对象就叫做原型对象(额外提一下,每个原型对象都有constructor属性,这个属性指回构造函数),这个对象上的所有属性和方法都可以被这个函数构造出来的对象所使用。这一点就类似于面向对象语言的继承,如下代码:
function Person() {
}
Person.prototype.sex = '男'
let man = new Person()
console.log(man.sex);//打印'男'
构造函数Person内没有没有sex这个属性,但man可以使用他原型对象上的属性
二、原型链:
在js中,每个对象和函数都会初始化__proto__这个属性。前面有说过new关键字的作用,它将对象内的__proto__属性指向原型对象,而每一个原型对象都是由Object函数构造出来的。所以原型对象的__proto__属性就会指向Object的原型(prototype),也就是指向Object.prototype对象,但原型链的最终指向是null,所以Object.prototype的__proto___属性指向的是null。这就构成一条链式结构,也就是原型链。
如下图:
误区:很多第一次学习js的同志在学习原型链时,以为实例化对象的__proto__始终指向构造函数的原型对象(构造函数.prototype)。当实例化对象后,修改原型对象的指向后,就构成新的原型链。
如下图:
function Person() {
}
function Animal() {
}
Animal.prototype.say = 'I can say'
Person.prototype.sex = '男'
let man = new Person()
Person.prototype = new Animal();
console.log(man.say);//undefined
console.log(man.__proto__==Person.prototype);//false
console.log(man.__proto__.__proto__==Object.prototype);//true
console.log(Person.prototype.__proto__==Animal.prototype);//true
man原本的原型链:
从man.__proto__==Person.prototype的结果为false上来看,很明显,man对象的原型链并没有修改,并且无法访问Animal.prototype身上的属性。因为,man的__proto__属性指向的地址并没有发生改变,只是Person.prototype通过new关键字被赋予了新的地址,使得Person.prototype的__proto__属性指向了Animal.prototype。所以man对象的__proto__属性指向的对象的__proto__指向的地址没有发生改变,所以原型链并没有被修改。
解决这种情况也很简单,只要将Person.prototype的地址重新赋予man的__proto__属性,使__proto__重新指向Person.prototype就能修改man对象的原型链,可以访问Animal.prototype身上的属性和方法。
如下图:
man.__proto__=Person.prototype;
console.log(man.say);//'I can say'
修改man的__pro__的指向后的原型链:
三、Function函数:
在js中,函数是一种特殊的对象,所以函数有一条特殊的原型链。函数都是由Function构造出来的,并且Function是由Function本身构造出来的。所以函数的__proto__属性指向Function.prototype,然而所有的原型对象都是由Object构造出来的,并且Object也是由Function构造出来的,所以有以下关系:
console.log(Function.__proto__==Function.prototype);//true
console.log(Function.__proto__.__proto__==Object.prototype);//true
console.log(Object.__proto__==Function.prototype);//true
可能代码比较难理解,不容易看出Function和Object之间的关系
介绍到这里,想必原本对原型和原型链都懵懵懂懂的看官都会有更清楚的理解。
四、总结:
在js中不管是哪条原型链,最终指向都是Object.prototype。