- prototype
我们来对比一下两种把 Bar.prototype 关联到 Foo.prototype 的方法:
// ES6 之前需要抛弃默认的 Bar.prototype
Bar.ptototype = Object.create( Foo.prototype );
// ES6 开始可以直接修改现有的 Bar.prototype
Object.setPrototypeOf( Bar.prototype, Foo.prototype );
如果忽略掉 Object.create(..) 方法带来的轻微性能损失(抛弃的对象需要进行垃圾回
收),它实际上比 ES6 及其之后的方法更短而且可读性更高。不过无论如何,这是两种完
全不同的语法。 -
proto
.proto是绝大多数(不是所有!)浏览器也支持一种非标准的方法来访问内部 [[Prototype]] 属性:
a.__proto__ === Foo.prototype; // true
这个奇怪的 .proto (在 ES6 之前并不是标准!)属性“神奇地”引用了内部的
[[Prototype]] 对象,如果你想直接查找(甚至可以通过 .proto.ptoto... 来遍历)
原型链的话,这个方法非常有用。 - 原型链
现在我们知道了, [[Prototype]] 机制就是存在于对象中的一个内部链接,它会引用其他
对象。
通常来说,这个链接的作用是:如果在对象上没有找到需要的属性或者方法引用,引擎就
会继续在 [[Prototype]] 关联的对象上进行查找。同理,如果在后者中也没有找到需要的
引用就会继续查找它的 [[Prototype]] ,以此类推。这一系列对象的链接被称为“原型链”。
4.Object.create(..)
4.1 Object.create()使用
还记得吗,本章前面曾经说过 Object.create(..) 是一个大英雄,现在是时候来弄明白为
什么了:
var foo = {
something: function() {
console.log( "Tell me something good..." );
}
};
var bar = Object.create( foo );
bar.something(); // Tell me something good...
Object.create(..) 会创建一个新对象( bar )并把它关联到我们指定的对象( foo ),这样
我们就可以充分发挥 [[Prototype]] 机制的威力(委托)并且避免不必要的麻烦(比如使
用 new 的构造函数调用会生成 .prototype 和 .constructor 引用)。
我们并不需要类来创建两个对象之间的关系,只需要通过委托来关联对象就足够了。而
Object.create(..) 不包含任何“类的诡计”,所以它可以完美地创建我们想要的关联关系。
4.2 Object.create() 的polyfill代码
Object.create(..) 是在 ES5 中新增的函数,所以在 ES5 之前的环境中(比如旧 IE)如
果要支持这个功能的话就需要使用一段简单的 polyfill 代码,它部分实现了 Object.
create(..) 的功能:
if (!Object.create) {
Object.create = function(o) {
function F(){}
F.prototype = o;
return new F();
};
}
这段 polyfill 代码使用了一个一次性函数 F ,我们通过改写它的 .prototype 属性使其指向想
要关联的对象,然后再使用 new F() 来构造一个新对象进行关联。
5.继承
5.1 ES5中相对可用的两种继承方案
1.通过原型链实现继承
Child.prototype = new Parent()
在这种实现中,Parent中的静态属性不会被继承
不同的Child实例的proto会引用同一Parent的实例
2.构造函数实现继承
function Child(args) {
//..
Parent.call(this, args)
}
这样其只是实现了实例属性继承,Parent原型的方法在Child实例中并不可用
只有实现组合继承,Parent原型的方法在Child实例中才能基本可用
网友评论