先上张图
构造函数
上面的图看懂了么,没懂不要紧。先看个栗子:
function Foo() { }
Foo.prototype.name = 'haha'
const foo = new Foo()
const bar = new Foo()
console.log(foo.name) // haha
console.log(bar.name) // haha
没错,这个Foo
是构造函数,foo
是实例对象。嗯,继续往下看。
原型
-
prototype(原型对象)
prototype
:是一个对象,这个对象包含了所有实例对象共享的属性和方法。每个函数都有prototype
属性(除了bind、箭头函数、Function.prototype),但也只有函数才拥有这个属性。
我们把Foo.prototype
打印出来,可以看出它包含了实例对象foo 和 bar
共同的属性name = 'haha'
。constructor
和__proto__
当作没看到。哈哈,开玩笑,既然看到了,就分析下这两妖孽是啥。 -
__proto__(原型指针)
__proto__
:每个js
对象都有这个属性(除了null
),顾名思义,它指向的是该实例对象的原型对象。比如说,栗子中实例对象foo
的__proto__
就是Foo.prototype
。js console.log(foo.__proto__ === Foo.prototype) // true
-
constructor
constructor
:每个prototype
原型都有个constructor
,它指向的是构造函数。上面栗子中Foo.prototype
的constructor
就是构造函数Foo
。js console.log(Foo.prototype.constructor === Foo) // true
原型链
以上,我们可以看出构造函数、原型对象、实例之间的关系。每个构造函数都有一个原型对象(prototype
),原型对象都包含一个指向构造函数的指针(constructor
),而每个实例都包含一个指向原型对象的指针(__proto__
)。
如果原型对象(prototype
)是个实例呢,这样我们通过Foo.prototype.__proto__
又会找到另一个原型对象(Object.prototype
)。如此层层递进,实例与原型就形成了一个链条,这就是原型链。
console.log(Foo.prototype.__proto__ === Object.prototype) // true
来自于生命起源的问题,先有鸡还是先有蛋
console.log(Function.__proto__ === Function.prototype) // true
console.log(Function.__proto__.__proto__ === Object.prototype) // true
console.log(Object.__proto__ === Function.prototype) // true
有兴趣的可以看看知乎上的讨论