原型和原型链
function Foo() {}
let f1 = new Foo()
- 普通对象有__proto__和constructor
- 函数对象有__proto__、prototype和constructor
首先解释下,JS标准中对象并没有区分普通对象和函数对象,但现实中我们确实可以这样划分(其实在各种库中,我们经常能看到判断是否是普通对象的方法,而它们的名称往往是isPlainObject),以便于接下来的讨论和理解
说到原型和原型链,其实都是针对构造函数和实例而言的,构造函数也可能是其他构造函数的一个实例
- Foo是一个构造函数,属于函数对象
- f1是Foo的实例,属于普通对象
原型链的方向
原型链是通过__proto__连接的,逐层向上寻找,但普通对象和函数对象最终的方向有些差异
-
普通对象
- f1 -> Foo.prototype -> Object.prototype(这里可以解释普通对象上可以访问到toString、valueOf、hasOwnProperty等等方法) -> null
-
函数对象
-
Foo -> Function.prototype(这里可以解释函数可以调用到apply、call、bind等方法) -> Object.prototype(这里可以解释函数上可以访问到toString、valueOf、hasOwnProperty等等方法) -> null
-
解释下,Function.prototype.__proto__指向Object.prototype,这个逻辑是JS本身就是这么设计的
-
Object也属于函数对象,Object.__proto__指向Function.prototype,这个也是JS本身设计如此
- Object.proto = Function.prototype
- Object.constructor = Function
- Object.prototype = Object.prototype
- Object.prototype.constructor = Object
-
构造函数的方向
这里可能要区分下
-
实例和构造函数之间通过constrcutor连接
- f1 -> Foo -> Function <-> Function
- Object -> Function
-
原型对象和构造函数之间通过constructor连接
- Foo.prototype -> Foo
- Object.prototype -> Object
- Function.prototype -> Fucntion