Prototype机制就是存在于对象中的一个内部链接,它会引用其他对象。
通常来说,这个链接的作用是:如果在对象上没有找到需要的属性或者方法引用,引擎就会继续在Prototype关联的对象上进行查找。同理,如果在后者中也没有找到需要的引用就会继续查找它的Prototype,以此类推。这一系列对象的链接被称为“原型链”。
当你通过各种语法进行属性查找时都会查找Prototype链,直到找到属性或者查找完整条原型链。所有普通的Prototype链最终都会指向内置的Object.prototype
类函数
虽然JavaScript机制和传统面向类语言中的“类初始化”和“类继承”很相似,但是JavaScript中的机制有一个核心区别,那就是不会进行复制,对象之间是通过内部的Prototype链关联的。
继承意味着复制操作,JavaScript(默认)并不会复制对象属性。相反,JavaScript会在两个对象之间创建一个关联,这样一个对象就可以通过委托访问另一个对象的属性和函数。
构造函数
当你在普通的函数调用前面加上new关键字之后,就会把这个函数调用变成一个“构造函数调用”。实际上,new会劫持所有普通函数并用构造对象的形式来调用它。换句话说,在JavaScript中对于“构造函数”最准确的解释是,所有带new的函数调用。
a.constructor === Foo为真意味着a确实有一个指向Foo的.constructor属性,但是事实不是这样。
实际上,.constructor引用同样被委托给了Foo.prototype,而Foo.prototype.constructor默认指向Foo。
把.constructor属性指向Foo看作是a对象由Foo“构造”非常容易理解,但这只不过是一种虚假的安全感。a.constructor只是通过默认的Prototype委托指向Foo,这和“构造”毫无关系。
最好的办法是记住这一点:“constructor并不表示被构造”。
1 | function Foo() { /* .. */ } |
原型继承
ES6添加了辅助函数Object.setPrototypeOf(..),可以用标准并且可靠的方法来修改关联。
1 | // ES6之前需要抛弃默认的Bar.prototype |