每一个函数都有一个 .prototype 属性(“function”.prototype),.prototype指向一个对象,“function”.prototype的名字就是原型对象。
举个例子
//这是一个构造函数(构造函数也是函数)
const Persion(name,money){this.name = name;this.money = money
}
那么Persion身上就有一个prototype 例如↓
Persion.prototype
保存公共状态
举个例子
有那么一个需求,name和sex自定义。money字段共用且固定
//第一个构造函数
const Person(name,sex){this.name = name;this.sex = sex;
}
Person.prototype.money = 0;
const per1 = new Person('阿巴',"男");
const per2 = new Person('呱啦',"女");
per1.money===0//true
per2.money===0//true
per1和per2在本身找不到money这个属性的时候就会去其构造函数的原型对象上面寻找这个属性。而money这个属性被挂载的Person的原型对象上(也就是per1和per2构造函数都原型上) ,per1和per2又是Person的实例。所以per1和per2可以在本身没有money的情况下访问到money这个变量。
per1和per2都通过Person来构建实例。但只有他们的name和sex属性是不一样的。money属性就实现了共用。
在原型对象这个对象上,有一个属性 .constructor 指向其原型对象所在的函数。
拿上面的案例举个例子
Person.prototype.constructor === Person //true
这一整个概念,我们称之为原型。
我们上面介绍的prototype被称为显式原型。
还有一个隐式原型 __ proto__
__ proto__只存在于对象上。对象的__proto__(隐式原型)指向的就是其构造函数的显式原型。
例如↓
const Person(name,sex){this.name = name;this.sex = sex;
}
const per = new Person("阿巴","男");
per.__ proto __==== Person.prototype//true
per.__ proto__(隐式原型)指向Person.prototype(显示原型),
但Person.prototype这个原型对象也是一个对象,他也有一个自己的__proto__属性。
那Persion.prototype.proto(原型对象中的__proto__)指向哪里呢;
对象的构造函数是 Object()。
当我们需要创建的一个对象的时候,是不是可以 通过
const obj = Object();
这种方式来构建一个对象。
所以,原型对象的隐式原型(xxx.prototype.proto)指向的就是对象构造函数的显式原型(Object.prototype);
而这一个逐级向上寻找的过程被称为原型链。
举个例子
Object.prototype.result = "遗憾";
const Person(name,love) {this.name = name;this.she = love;
}
const per = new Person("我","她");
per.result === "遗憾"//true
上面这个例子中,per本身没有result属性,Person的显示原型上面也没有result属性,但是Object的显示原型上有这个属性。
per在访问result这个属性的时候会先在本身找
本身没有,会访问自己的__proto__(自己的隐式原型指向自己构造函数的显示原型)去自己构造函数的显示原型上找(也就是Person.prototype);
自己构造函数的显示原型(也就是Person.prototype)上没有就会访问构造函数的显示原型中的隐式原型(也就是Person.prototype.proto)从而找到Object的显式原型(Object.prototype)
最后在Object.prototype中找到了 result 属性,从而返回result。
如果一直找到Object.prototype仍未寻找到想要的值,会返回null;
Object.prototype.__proto__ === null//true
原型对象的隐式原型指向其构造函数的显式原型。但是因为Object.显式原型已经到头了。没有更上一层了。所以Object.prototype.__proto__指向null