原型链
井然有序的原型链

Function和Object的关系


实例之间的关系
foo instanceof Foo // true
Foo instanceof Function // true
Function.prototype instanceof Object // true
// Object是Object的实例
Object instanceof Object // true(Object.__proto__.__proto__ === Object.prototype)
// Object是Function的实例
Object instanceof Function // true(Object.__proto__ === Function.prototype)
// Function是Object的实例
Function instanceof Object // true(Function.__proto__.__proto__ === Object.prototype)
// Function是Function的实例
Function instanceof Function // true(Function.__proto__ === Function.prototype)
鸡生蛋 蛋生鸡问题
// Function是Function的实例
Function instanceof Function
Function.__proto__ === Function.prototype
此处争论点在于 Function 对象是不是由 Function 构造函数创建的一个实例?
解释 1、YES:按照 JavaScript 中“实例”的定义,a 是 b 的实例即 a instanceof b 为 true,默认判断条件就是 b.prototype 在 a 的原型链上。而 Function instanceof Function 为 true,本质上即 Object.getPrototypeOf(Function) === Function.prototype,正符合此定义。
解释 2、NO:Function 是 built-in 的对象,也就是并不存在“Function对象由Function构造函数创建”这样显然会造成鸡生蛋蛋生鸡的问题。实际上,当你直接写一个函数时(如 function f() {} 或 x => x),也不存在调用 Function 构造器,只有在显式调用 Function 构造器时(如 new Function('x', 'return x') )才有。
倾向于把 Function.__proto__ 指向 Function.prototype 是为了保证原型链的完整,让 Function 可以获取定义在 Object.prototype 上的方法。
作用域链和原型继承查找时的区别
如果去查找一个普通对象的属性,但是在当前对象和其原型中都找不到时,会返回undefined。但查找的属性在作用域链中不存在的话就会抛出ReferenceError。
其他
1、prototype是函数才有的属性 但不是所有的函数都有的属性
a.函数作为构造函数(有)
b.函数作为普通函数(有)
c.原型函数(没有)
2.__proto__是实例拥有的属性,可以用A instanceof B来判断A是否是B的实例。instanceof原理参考 第10期 instanceof实现原理。例如此处foo是Foo的实例,因为foo.__proto__ === Foo.prototype。
3.__proto__ 属性在 ES6 时才被标准化,以确保 Web 浏览器的兼容性,但是不推荐使用,除了标准化的原因之外还有性能问题。为了更好的支持,推荐使用 Object.getPrototypeOf()。
通过改变一个对象的 [[Prototype]] 属性来改变和继承属性会对性能造成非常严重的影响,并且性能消耗的时间也不是简单的花费在 obj.__proto__ = ... 语句上, 它还会影响到所有继承自该 [[Prototype]] 的对象,如果你关心性能,你就不应该修改一个对象的 [[Prototype]]。如果要读取或修改对象的 [[Prototype]] 属性,建议使用如下方案,但是此时设置对象的 [[Prototype]] 依旧是一个缓慢的操作,如果性能是一个问题,就要避免这种操作。
// 获取
Object.getPrototypeOf()
Reflect.getPrototypeOf()
// 修改
Object.setPrototypeOf()
Reflect.setPrototypeOf()
如果要创建一个新对象,同时继承另一个对象的 [[Prototype]] ,推荐使用 Object.create()。
引用类型 constructor 属性值是可以修改的,但是对于基本类型来说是只读的,当然 null 和 undefined 没有 constructor 属性。
不要使用 Bar.prototype = Foo,因为这不会执行 Foo 的原型,而是指向函数 Foo。
4、原型链的构建是依赖于 prototype 还是 __proto__?
__proto__