理解原型对象与其实例之间是一对多的关系,对于实现正确的对象行为很重要。
常见的错误是不小心将每个实例的数据存储到了其原型中。

示例

一个实现了树型数据结构的类可能将子节点存储在数组中。

实例状态在原型中(错误)

将存储子节点的数组放置在原型对象中将会导致实现被完全破坏。

function Tree(x){
this.value=x;
}
Tree.prototype={
children:[],
addChild:function(x){
this.children.push(x);
}
}

如果我们使用这个类构造一棵树,代码如下

var left=new Tree(2);
left.addChild(1);
left.addChild(3); var right=new Tree(6);
right.addChild(5);
right.addChild(7); var main=new Tree(4);
main.addChild(left);
main.addChild(right); main.children;//[1,3,5,7,left,right]

我们预想的main.children应该是只包括left,right两个Tree的实例的,为什么包括这些了呢?
看一下下面这张图就明白了

这里面原有的实例都要可以访问和操作原型中children,然后都是对这个数组进行了添加,导致对应实例的children数据出现错误。

实例状态在实例对象中(正确)

实现Tree类的正确方式是为每个实例创建一个单独的children数组。

function Tree(x){
this.value=x;
this.children=[];
}
Tree.prototype={
addChild:function(){
this.children.push(x);
}
}

同样的我们看一张上面代码的图示

分析

共享有状态的数据可能会导致错误。通常在一个类的多个实例之间共享方法是安全的,因为方法通常是无状态的,这不同于通过this来引用实例状态。(因为方法调用的语法确保了this被绑定到实例对象,即使该方法是从原型中继承来的,共享方法仍然可以访问实例状态)一般情况下,任何不可变的数据可以被存储在原型中从而被安全地共享。有状态的数据原则上也可以存储在原型中,只要你真正想共享它。在原型中最常见的数据是方法,而每个实例的状态都存储在实例对象中。

提示

  • 共享可变数据可能会出现问题,因为原型是被其所有的实例共享的

  • 将可变的实例状态存储在实例对象中

[Effective JavaScript 笔记]第36条:只将实例状态存储在实例对象中的更多相关文章

  1. [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象

    js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...

  2. [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符

    “1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...

  3. [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

    函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...

  4. [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

    js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...

  5. [Effective JavaScript 笔记]第65条:不要在计算时阻塞事件队列

    第61条解释了异步API怎样帮助我们防止一段程序阻塞应用程序的事件队列.使用下面代码,可以很容易使一个应用程序陷入泥潭. while(true){} 而且它并不需要一个无限循环来写一个缓慢的程序.代码 ...

  6. [Effective JavaScript 笔记]第46条:使用数组而不要使用字典来存储有序集合

    对象属性无序性 js对象是一个无序属性集合. var obj={}; obj.a=10; obj.b=30; 属性a和属性b并没有谁前谁后之说.for...in循环,先输出哪个属性都有可能.获取和设置 ...

  7. [Effective JavaScript 笔记]第55条:接收关键字参数的选项对象

    53节建议保持参数顺序的一致约定对于帮助程序员记住每个参数在函数调用中的意义很重要.参数较少这个主意不错,但如果参数过多后,就出现麻烦了,记忆和理解起来都不太容易. 参数蔓延 如下面这些代码: var ...

  8. [Effective JavaScript 笔记]第20条:使用call方法自定义接收者来调用方法

    不好的实践 函数或方法的接收者(即绑定到特殊关键字this的值)是由调用者的语法决定的.方法调用语法将方法被查找的对象绑定到this变量,(可参阅之前文章<理解函数调用.方法调用及构造函数调用之 ...

  9. [Effective JavaScript 笔记]第23条:永远不要修改arguments对象

    arguments对象并不是标准的Array类型的实例.arguments对象不能直接调用Array方法. arguments对象的救星call方法 使得arguments可以品尝到数组方法的美味,知 ...

随机推荐

  1. [BZOJ 1797][AHOI2009]最小割(最小割关键边的判断)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1797 分析: 在残余网络中看: 对于第1问: 1.首先这个边必须是满流 2.其次这个边 ...

  2. java网络编程基础

    前言 通过网络进行数据传输时,一般使用TCP/UDP进行数据传输.但是两个的区别就是TCP可靠,UDP不可靠.两个的共同之处就是都需要建立socket套接字,将IP地址和端口port进行绑定.但是服务 ...

  3. java中的File类

    File类 java中的File类其实和文件并没有多大关系,它更像一个对文件路径描述的类.它即可以代表某个路径下的特定文件,也可以用来表示该路径的下的所有文件,所以我们不要被它的表象所迷惑.对文件的真 ...

  4. 【OpenCV入门教程之一】 安装OpenCV:OpenCV 3.0 +VS 2013 开发环境配置

    图片太多,具体过程参照: [OpenCV入门教程之一] 安装OpenCV:OpenCV 3.0.OpenCV 2.4.8.OpenCV 2.4.9 +VS 开发环境配置 说下我这边的设置: 选择deb ...

  5. tomcat服务器上webapps里的文件名和项目名称不一样,修改方法

    第一种方法:打开工程所在目录,找到一个 .mymetadata的文件,用记事本等打开,内容大致如下: <?xml version="1.0" encoding="U ...

  6. winform之权限判断小技巧

    每个页面都要判断用户是否登陆并且判断用户是否拥有相应的权限,,以至于每个页面都要判断Session["user"]是否为空,后期不好维护 小技巧: 因为每个页面都继承与Page类, ...

  7. SQL Network Interfaces, error: 50 - 发生了 Local Database Runtime 错误。无法创建自动实例。

    今天在用VS2013自带的LocalDB调整数据库时出错,在网上也搜到许多方案,如卸载SQLServer LocalDB的程序.重新创建实例等都没有解决我的问题,也重新修改以及修复Vs,问题依旧存在, ...

  8. Windows Server 2008 显示桌面图标

    相信有朋友们有安装使用过windows 2008 server服务器,刚安装好的时候,桌面上只有一个回收站的图标,它没有像windows 7或windows 8一样可以直接通过右击鼠标的菜单来设置,要 ...

  9. POJ 1625 Censored!

    辣鸡OI毁我青春 Description The alphabet of Freeland consists of exactly N letters. Each sentence of Freela ...

  10. 使用python来调试串口

    串口模块的波特率比较特别,找了几个串口工具都不支持...所以,干脆用python自己来写了,其实已经好奇好久了,别人的工具各种不顺手. 需要pyserial的支持,兼容各种平台,不需要新编译二进制文件 ...