prototype/__proto__
每个函数都有一个prototype属性,但是只有构造函数的prototype才有用。那么函数的prototype指向哪儿呢?
function Person(){}
console.log(Person.prototype===new Person().__proto__) //true
当构造函数被调用的时候会创建实例的原型,就像构造函数Person是全人类,那么实例的原型就是有具体特征的人群体,实例就是一个继承了这些特征的人。
每个函数有prototype指向实例的原型,实例的原型又有constructor指向函数就可以得出:
function Person(){}
console.log(Person===Person.prototype.constructor) //true
再结合实例有__proto__指向实例原型得出下面的图
那么多出来个实例原型有什么用呢?
有用,非常有用!!
function Person(name,age,sex){
this.name=name;
this.age=age;
this.sex=sex;
this.sayHello=function(){
console.log('hello')
}
}
let xiaoming=new Person('xiaoming',13,'male');
let xiaohong=new Person('xiaohong',15,'female');
把上面代码拷进编辑器,我们看看xiaoming.sayHello和xiaohong.sayHello是不是同一个函数,很明显不是,多一个实例就要多创建一个sayHello函数,多一百个就要多创建一百个,明明我们都只是想打印hello呀,有没有办法所有人公用一个sayHello函数呢,还真有。
function Person(name,age,sex){
this.name=name;
this.age=age;
this.sex=sex;
}
Person.prototype.sayHello=function(){console.log('hello')}
let xiaoming=new Person('xiaoming',13,'male');
let xiaohong=new Person('xiaohong',15,'female');
console.log(xiaoming.sayHello===xiaohong.sayHello) //true
我们把共有可复用的函数挂在到实例的原型上,利用实例会自动向原型链上找东西的特性,以后每个人都可以拿来用,节约了内存空间。
既然说到原型链了,我们就找找原型链的终点
function getPrototypeChain(obj) {
const protoChain = [];
while ((obj = Object.getPrototypeOf(obj))) {
protoChain.push(obj);
}
console.log(protoChain);
}
getPrototypeChain(xiaoming);
用上面代码扒一下,出现如下结果,又试了试Array能扒下什么,出现Array函数和Object那么基本可以确定原型链终点是Object.prototype了,可以得出如下原型链图片。
图片中红色的便是原型链。