开发者社区> 华章计算机> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

《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社区中的大部分开发者看来,将所有属性(不包括方法)都搬至原型上做共享,是一种非常危险的编码反模式,因为实际应用中,多数代码异常事故都源于对共享属性的意外修改。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
js轮播图实现透明度切换
涉及知识点:js、轮播图、透明度、js透明度切换轮播图。
17 0
js实现python的random.choice
js实现python的random.choice
10 0
js: 实现一个cached缓存函数计算结果
js: 实现一个cached缓存函数计算结果
22 0
js实现页面滑动到最底部触发内容加载
js实现页面滑动到最底部触发内容加载
19 0
通过JS实现Json序列化操作
分享JS实现的JSON序列化操作
13 0
实现一个糊弄人的进度条layui+js
众所周知,进度条是一种烦人的东西╭(╯^╰)╮ 它用于实时显示处理任务的速度,完成度,剩余未完成任务量的大小,和可能需要处理时间。下面来一起写一个进度条叭
15 0
js实现css、addClass、removeClass和toggleClass
JQuery中获取CSS样式css(name):访问第一匹配元素的样式属性css(name,value):在所有匹配的元素中,设置一个样式属性的值css(properties):把一个“名/值对”对象设置为所有匹配元素的样式属性css(name,function(index,value)):在所有匹...
684 0
10057
文章
0
问答
来源圈子
更多
+ 订阅
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载