prototype
是什么?
每个函数都有一个特殊的属性叫做原型(prototype),这个属性的值是一个对象。即:原型指向一个对象,这个对象包含所有实例共享的属性和方法
作用
可以让所有对象实例共享一些属性和方法
constructor
原型对象里有一个 constructor
属性,它指回该原型对象所在的函数
当有一个对象,但不知道它使用了哪个构造器(例如它来自第三方库),并且需要创建另一个类似的对象时,用这种方法就很方便。但是 constructor 是可以被修改的,所以不是绝对安全。
函数的 prototype 可以被修改,但是不影响之前已经通过函数 new 出来的对象的
[[Prototype]]
,只会影响后面新创建的对象的[[Prototype]]
指向
__proto__
是什么?
每个对象实例(包括 函数 和 prototype 对象)都有一个隐藏属性 [[Prototype]]
(显式名称:__proto__
,__proto__
是一种访问 [[Prototype]]
的方式,而不是 [[prototype]]
本身,是 [[prototype]]
的访问器属性):指向它的 构造函数 的 原型对象(prototype)
作用
继承原型上的属性和方法,构成原型链,实现基于原型的继承
可以通过给一个对象的 __proto__
赋值来设置这个对象的原型,但是有 2 个限制:
- 不能形成闭环
__proto__
的值可以是 对象 或 null,其他的类型都会被忽略
__proto__
是历史遗留的,最好使用Object.getPrototypeOf()
和Object.setPrototypeOf()
来操作原型
Warning
更改原型是一个非常缓慢的操作,因为它破坏了对象属性访问操作的内部优化
NOTE
可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。
因为:当为对象实例添加一个与原型对象中同名的属性时,这个属性就会屏蔽原型对象中的同名属性,而不会修改它。
delete 操作是直接作用于对象的,也不会删除原型上的属性
原型链
- 当要查找对象的某个属性时,会先查找对象本身是否存在该属性,如果存在就找到了返回,
- 如果不存在,就会在它的
__proto__
所指的原型对象中寻找, - 同样,原型对象也有
__proto__
,这样一层一层向上查找, - 最终查找到
Object.prototype.__proto__
为 null 的终点时查找完成,就构成了原型链。
instanceof
obj instanceof constructor
:检查 obj 的原型链 上是否有 constructor.prototype
即:判断某个构造函数的 prototype 属性是否出现在某个实例对象的 原型链 上
this
this 不受原型链影响,就算调用的是原型上的方法,其方法内部的 this 也按照 this 绑定原则进行设置
没有 __proto__ 的对象
Object.create(null)
可以创建一个空对象,这个对象没有原型([[Prototype]]
是 null)
把这样的对象称为 “very plain” 或 “pure dictionary” 对象,它们甚至比通常的普通对象(plain object)
{...}
还要简单