《JavaScript应用程序设计》一一3.4原型代理

    xiaoxiao2023-06-12  170

    本节书摘来华章计算机出版社《JavaScript应用程序设计》一书中的第3章,第3.4节,作者:Eric Elliott 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

    3.4 原型代理

    在JavaScript中,所有对象内部都有一个指向其原型的引用,在获取对象的属性与方法时,JavaScript引擎会首先检索当前对象是否有值,如果没有则去检索其原型,如果还没有,再沿着原型链的上游继续查找,直到抵达原型链的末端,也就是Object对象的原型上。当创建了一个对象字面量时,会隐式地将其与Object的原型关联起来。或者,你可以通过Object.create()方法构造对象,此方法允许你为对象设置原型。Object.create()方法在ES5规范中才被加入,所以可能你需要自己去实现它。下面是MDN(Mozilla Developer Network)文档中一项对Object.create()方法的实现(http://mzl.la/1pFH3jo):

    if (!Object.create) { Object.create = function (o) { if (arguments.length > 1) { throw new Error('Object.create implementation' + ' only accepts the first parameter.'); } function F() {} F.prototype = o; return new F(); }; }

    当你通过new关键字调用构造函数时,构造函数的原型对象会被设置为新实例对象原型的引用。如你所见,Object.create()的模拟方案仅仅是一个快捷方式,它先是创建了一个新的构造函数,随后将传入的对象赋值给构造函数的原型,最后返回由原型生成的实例。下面来看看如何在实际场景中使用这个方案。

    var switchProto = { isOn: function isOn() { return this.state; }, toggle: function toggle() { this.state = !this.state; return this; }, state: false }, switch1 = Object.create(switchProto), switch2 = Object.create(switchProto); test('Object.create', function () { ok(switch1.toggle().isOn(), '.toggle() works.' ); ok(!switch2.isOn(), 'instance safe.' ); });

    被传入Object.create()方法中的任何对象,都会被视为新实例对象的原型,相信你也发现了,这个原型对象有一些不寻常之处。注意原型中的state值,更改实例switch1上的state值不会影响实例switch2中的state值。原型上的属性好比是默认值一样,会被实例对象中的同名属性所覆盖。需要特别留意的是,如果你在实例中对原型上的一些引用类型的变量(如对象或数组)做了修改,那么此项修改会在所有使用该原型的实例上生效,但如果你直接替换了实例中的某个属性值,所产生的修改影响仅限于实例本身。

    var switchProto = { isOn: function isOn() { return this.state; }, toggle: function toggle() { this.state = !this.state; return this; }, meta: { name: 'Light switch' }, state: false }, switch1 = Object.create(switchProto), switch2 = Object.create(switchProto); test('Prototype mutations.', function () { switch2.meta.name = 'Breaker switch'; equal(switch1.meta.name, 'Breaker switch', 'Object and array mutations are shared.' ); switch2.meta = { name: 'Power switch' }; equal(switch1.meta.name, 'Breaker switch', 'Property replacement is instance-specific.' ); });

    在这个例子中,switchProto对象拥有一个名为meta的属性,当你在实例中对meta的子属性值进行修改时,所有原型链中关联对象的子属性值都会被改写,但如果你将实例中的meta对象直接替换为一个新对象时,改动效果仅仅限于实例本身。警告: 在JavaScript社区中的大部分开发者看来,将所有属性(不包括方法)都搬至原型上做共享,是一种非常危险的编码反模式,因为实际应用中,多数代码异常事故都源于对共享属性的意外修改。

    相关资源:JavaScript高级程序设计(附源码)
    最新回复(0)