function Foo (name) {
this.name
}
Foo.prototype.callMyName = function () {
console.log(this.name)
}
const f = new Foo('雪树')
f.callMyName() // 雪树
创建f
的过程和手写new
是一致的。
首先明确的是:
f
是对象,不是函数
Foo
是对象,也是函数
prototype
是函数特有的
__proto__
和constructor
是对象和函数都拥有的
prototype
由函数本身所构造产生。(我是这样理解的,或者说prototype
的构造函数指向函数本身,obj.prototype.constructor === obj
)
__proto__
指向该对象的构造函数的原型对象。即obj.__proto__ === obj.constructor.prototype
,先不考虑Object.create
constructor
说明了对象的来源
下面的代码和文字解释:
- 构造函数
首先很明显:f
由Foo
构造而来,f
的constructor
就是Foo
console.log(f.constructor); // [Function: Foo]
console.log(f.constructor === Foo); // true
Foo
的构造函数呢,其实就是Function
console.log(Foo.constructor); // [Function: Function]
事情从这里开始变得有意思:Foo
的构造函数是Function
,Function
的构造函数是他自己,即:
console.log(Foo.constructor); // [Function: Function]
console.log(Foo.constructor.constructor); // [Function: Function]
console.log(Foo.constructor.constructor.constructor); // [Function: Function]
console.log(Foo.constructor === Foo.constructor.constructor.constructor); // true
自己生自己的神奇函数。也意味着构造函数这条链走到了他的尽头。
- 原型对象
prototype
prototype
由函数本身构造而来(除非有修改指向的操作),因此有下等式:
Foo.prototype.constructor === Foo // true
我们为什么不用f
呢?
别忘了,f
是个对象,不是函数,但prototype
是函数特有的属性
为什么prototype
是函数特有的属性呢?
这就要从JS
的继承思想开始讲了,prototype
是为构造函数而设计的,在有prototype
之前,所有从同一个构造函数创建的实例,都无法共享属性和方法,这无疑是对资源的极大浪费。有了prototype
,所有构造函数的实例都可以共享prototype
上的属性和方法。
换言之,对象就不该有prototype
属性,对象又不用来构造实例。
- 隐式原型
__proto__
__proto__ === constructor.prototype
使得实例可以使用其构造函数的属性和方法
console.log(f.hasOwnProperty('callMyName')); // false
console.log(f.__proto__.hasOwnProperty('callMyName')); // true
f
调用了callMyName
,但实际上callMyName
不是f
自己的方法。
既然callMyName
不属于f
本身,那属于谁呢?
我们知道callMyName
属于Foo
的原型Foo.prototype
,f
就是通过f.__proto__
拿到callMyName
的
还记得f.__proto__ === Foo.prototype
吗。
关于__proto__
也有一条链
每个对象的__proto__
都指向自己的构造函数的原型对象(除了Function.prototype
和Object.prototype
)
f.__proto__ === Foo.prototype
Foo.prototype.__proto__ === Function.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null
特别的:
注意Function
和Function.prototype
的构造函数都是Function
但是
Function.prototype.__proto__
指向Object.prototype
Object
的构造函数是Function
Object.prototype
的构造函数是Object
但是Object.prototype.__proto__
指向null
有待补充。