原型
概念
- 原型就是一个概念
- 每个函数都有一个
prototype属性,该属性指向当前函数的显示原型对象,指向Object对象 - 每个实例对象都有一个
__proto__属性,该属性指向当前实例对象的隐示原型对象,指向Object对象 - 构造函数的显示对象 === 当前构造函数的实例对象的隐示原型对象
把一个构造函数可以看成一个类,原型是所有类都有的一个属性,原型的作用就是给这个类的每一个对象都添加一个统一的方法。
在es5时候我们通常使用大写开始的函数作为构造函数。
// 创建一个原型对象function Person() { }//1、 每个函数都有一个Prototypeconsole.log(Person.prototype); // {constructor: ƒ} 空对象 ==>原型对象Object对象(显示对象)、console.log(Person.prototype.constructor); //指向原型对象本身// 声明当前的构造函数console.log(Person.prototype.constructor); // 指向函数本身// 创建一个实例let person = new Person()// 2、 每个实例对象都有一个__proto__属性,这个属性指向当前对象的原型对象(隐式对象)// 3、构造函数的显示对象===实例的隐式对象console.log(Person.prototype === person.__proto__); // true
显示原型vs隐式原型
每个函数都有一个
prototype为显示原型。而每个实例都有__proto__,称为隐示原型。对象的隐示对象的值为构造函数显示对象的值。Person.prototype === person.__proto__。
- 函数的prototype属性:在定义函数时自动添加,默认为
空Object对象 - 对象的
__proto__属性:创建时自动添加,默认为构造函数的prototype属性值 - 我们能直接操作
显示对象而不能直接操作隐示对象
问:为什么
prototype创建出来的叫显示原型,而__proto__叫隐示原型?而不能直接操作隐示原型呢?
// 创建一个构造函数function Person(){}//问 为什么不是使用__proto__ 而是使用prototype呢Person.prototype.eat = function(){return '吃饭'}let person = new Person()person.__proto__.eat = function(){return '吃饭'}
对象的属性中,不加的属性/方法是内置对象意味着我们可以直接去调用,而加开头的我们是不可以直接使用的。所以__proto__是不可以直接使用的,所以才叫做隐示。
什么时候用到原型
但需要操作公共方法的时候可以直接放在原型对象上,供所有的实例对象使用,可以节省内存开销。
原型链
概念
- 查找对象属性的时候先在自身查找,如果自身没有该属性,会沿着
__proto__去原型对象查找,如果没有回返回undefined - 找到
Object的原型。如果没有返回undefined,如果调用的是函数,会返回is not function -
原型链示意图
实例对象vs函数对象
函数对象:可调用的对象,函数对象既可以点属性,又可以调用函数。
- 实例对象:所有的原型对象都是实例对象

