1. 除了用Function.prototype.bind()创建的函数没有prototype属性外,所有函数都有prototype属性。
例如,先声明一个函数:function Foo() {} 则函数Foo就被赋予了prototype属性,该属性的值是一个对象(也就是原型),并且只有一个属性constructor。constructor对应着构造函数,即Foo。
此时,一旦我们改变了函数的prototype,那么新对象就没有constructor这个属性了。
那么prototype属性有什么用呢,大部分时候是没用的, 大佬们认为该属性有两个作用:(1) 让实例对象知道是什么函数构造了它。 (2) 如果想给某些类库中的构造函数增加一些自定义的方法,就可以通过 xx.constructor.method 来扩展
2. 什么是__proto__
__proto__是所有对象都有的隐式属性,这个属性引用了创建该对象的函数的原型,即fn.__proto__ === Fn.prototype。因此,对于对象来说,xxx.__proto__.constructor是该对象的构造函数。
__proto__将对象和原型链接起来组成了原型链。有三点需要注意:
(1) 对象的原型的__proto__是null:Object.prototype.__proto__
(2) 既然对象是函数创建的,那么对象的__proto__要指向创建它的构造函数的原型: Object.__proto__ === Function.prototype
(3) 函数也是被Function创建的,那么函数的__proto__也应该指向Function的原型,这是一个环状结构,即函数的prototype和函数的__proto__指向同一个对象: Function.prototype === Function.__proto__
3. 关于Function.prototype这个特殊对象
若在控制台打印出这个对象,会发现该对象其实是一个函数:
Function.prototype其实是引擎自己创建的函数。首先引擎创建了 Object.prototype ,然后创建了 Function.prototype ,并且通过 __proto__ 将两者联系了起来。这里也很好的解释了上面的一个问题,为什么 let fun = Function.prototype.bind() 没有 prototype 属性。因为 Function.prototype 是引擎创建出来的对象,引擎认为不需要给这个对象添加 prototype 属性。
所以我们又可以得出一个结论,不是所有函数都是 new Function() 产生的。
有了 Function.prototype 以后才有了 function Function() ,然后其他的构造函数都是 function Function() 生成的。
总结:
1. Object是所有对象的爸爸,所有对象都可以通过__proto__找到它。
2. Function是所有函数的爸爸, 所有函数都可以通过prototype找到它。
3. Function.prototype和Object.Prototype是两个特殊的对象,他们由引擎来创建。
4. 除了以上两个对象外,其他对象都是由构造器new出来的。
5. 函数的prototype是一个对象,也就是原型。
6. 对象的__proto__指向原型,__proto__将对象和原型链接起来组成原型链。
附上图示: