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

简介:

本节书摘来华章计算机出版社《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 前端开发
js开发:请解释原型继承和类继承的区别。
JavaScript中的原型继承和类继承用于共享对象属性和方法。原型继承通过原型链实现共享,节省内存,但不支持私有属性。
270 0
|
JavaScript 前端开发
如何在JavaScript中实现基于原型的继承机制
【8月更文挑战第14天】如何在JavaScript中实现基于原型的继承机制
178 0
|
JavaScript 前端开发
JavaScript中的原型 保姆级文章一文搞懂
本文详细解析了JavaScript中的原型概念,从构造函数、原型对象、`__proto__`属性、`constructor`属性到原型链,层层递进地解释了JavaScript如何通过原型实现继承机制。适合初学者深入理解JS面向对象编程的核心原理。
357 1
JavaScript中的原型 保姆级文章一文搞懂
|
JSON JavaScript 前端开发
js原型继承|26
js原型继承|26
|
设计模式 JavaScript 前端开发
【JavaScript】深入浅出JavaScript继承机制:解密原型、原型链与面向对象实战攻略
JavaScript的继承机制基于原型链,它定义了对象属性和方法的查找规则。每个对象都有一个原型,通过原型链,对象能访问到构造函数原型上的方法。例如`Animal.prototype`上的`speak`方法可被`Animal`实例访问。原型链的尽头是`Object.prototype`,其`[[Prototype]]`为`null`。继承方式包括原型链继承(通过`Object.create`)、构造函数继承(使用`call`或`apply`)和组合继承(结合两者)。ES6的`class`语法是语法糖,但底层仍基于原型。继承选择应根据需求,理解原型链原理对JavaScript面向对象编程至关重要
517 7
【JavaScript】深入浅出JavaScript继承机制:解密原型、原型链与面向对象实战攻略
|
JavaScript 前端开发
JavaScript基础知识-原型(prototype)
关于JavaScript基础知识中原型(prototype)概念的介绍。
269 1
|
JavaScript 前端开发 Java
什么是JavaScript原型对象
【8月更文挑战第2天】什么是JavaScript原型对象
251 9
|
编解码 JavaScript 前端开发
JS逆向浏览器脱环境专题:事件学习和编写、DOM和BOM结构、指纹验证排查、代理自吐环境通杀环境检测、脱环境框架、脱环境插件解决
JS逆向浏览器脱环境专题:事件学习和编写、DOM和BOM结构、指纹验证排查、代理自吐环境通杀环境检测、脱环境框架、脱环境插件解决
1187 1
|
JavaScript 前端开发
JavaScript中什么是原型?有什么用?
JavaScript中什么是原型?有什么用?
208 1
|
JavaScript 前端开发
JavaScript prototype(原型对象)
JavaScript prototype(原型对象)
345 0

热门文章

最新文章