[Effective JavaScript 笔记]第36条:只将实例状态存储在实例对象中
理解原型对象与其实例之间是一对多的关系,对于实现正确的对象行为很重要。
常见的错误是不小心将每个实例的数据存储到了其原型中。
示例
一个实现了树型数据结构的类可能将子节点存储在数组中。
实例状态在原型中(错误)
将存储子节点的数组放置在原型对象中将会导致实现被完全破坏。
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条:只将实例状态存储在实例对象中的更多相关文章
- [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象
js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...
- [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符
“1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...
- [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码
函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...
- [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法
js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...
- [Effective JavaScript 笔记]第65条:不要在计算时阻塞事件队列
第61条解释了异步API怎样帮助我们防止一段程序阻塞应用程序的事件队列.使用下面代码,可以很容易使一个应用程序陷入泥潭. while(true){} 而且它并不需要一个无限循环来写一个缓慢的程序.代码 ...
- [Effective JavaScript 笔记]第46条:使用数组而不要使用字典来存储有序集合
对象属性无序性 js对象是一个无序属性集合. var obj={}; obj.a=10; obj.b=30; 属性a和属性b并没有谁前谁后之说.for...in循环,先输出哪个属性都有可能.获取和设置 ...
- [Effective JavaScript 笔记]第55条:接收关键字参数的选项对象
53节建议保持参数顺序的一致约定对于帮助程序员记住每个参数在函数调用中的意义很重要.参数较少这个主意不错,但如果参数过多后,就出现麻烦了,记忆和理解起来都不太容易. 参数蔓延 如下面这些代码: var ...
- [Effective JavaScript 笔记]第20条:使用call方法自定义接收者来调用方法
不好的实践 函数或方法的接收者(即绑定到特殊关键字this的值)是由调用者的语法决定的.方法调用语法将方法被查找的对象绑定到this变量,(可参阅之前文章<理解函数调用.方法调用及构造函数调用之 ...
- [Effective JavaScript 笔记]第23条:永远不要修改arguments对象
arguments对象并不是标准的Array类型的实例.arguments对象不能直接调用Array方法. arguments对象的救星call方法 使得arguments可以品尝到数组方法的美味,知 ...
随机推荐
- java heep space错误解决办法
1.双击tomcat 2.Open launch configuration 3.Argument 4. VM arguments中添加:-Xmx1024M -Xms512M -XX:MaxPermS ...
- 【WEB前端经验之谈】没有速成,只有不断积累。
2013年8月25日,我人生中的第一份正式工作开始了,第一份工作做的是当时学习的asp.net,用的是C#语言. 到第一家公司上班是公司是做一个OA系统,不过我去的时候大部分都已经完成了,剩下的都是细 ...
- How to use VS2012 remote debug Windows Azure Cloud Services
Background: Windows Azure Cloud Services 可以在本地调试,使用Visual Studio 2012 + 模拟器 Emulator.但是模拟器的工作状态和环境和真 ...
- 那天有个小孩跟我说LINQ(八)学会Func
文章已经迁移到:http://www.ayjs.net/2013/08/68/ 文章已经迁移到:http://www.ayjs.net/2013/08/68/ 文章已经迁移到:http://www.a ...
- C#线程模型脉络
今天在看同事新买到的<C#本质论 Edition 4>的时候,对比下以前Edtion3的新特性时针对Async/Await关键字时发现对一些线程方面的定义还理解的不是很透彻,脉络还不是很清 ...
- 9、面向对象以及winform的简单运用(输入输出流、图像的上传和读取)
一.输入输出流 1.概念: 输入输出流主要用于保存.读取文件,其内容保存在内存中. 2.使用方法: using System.IO; //System.IO 命名空间包含允许读写文件和数据流的类型以及 ...
- DOM(二)使用DOM
在了解DOM(文本对象模型)的框架和节点后,最重要的是使用这些节点处理html网页 对于一个DOM节点node,都有一系列的属性和方法可以使用.常用的有下表. 完善:http://www.w3scho ...
- java多线程-BlockingQueue
BlockingQueue简介 ArrayBlockingQueue:基于数组实现的一个阻塞队列,在创建ArrayBlockingQueue对象时必须制定容量大小.并且可以指定公平性与非公平性,默认情 ...
- Xamarin.Forms——尺寸大小(五 Dealing with sizes)
如之前所见的大量可视化元素均有自己的尺寸大小: iOS的状态栏高度为20,所以我们需要调整iOS的页面的Padding值,留出这个高度. BoxView设置它的默认宽度和高度为40. Frame的默认 ...
- PowerDesigner-制作Word导出模版
定制导出模版 当然这不是我们想要的word,下面看如何做一个自定义模版 1. 在工具栏中选择[Report -->Reports],如下图 点击第二个图标创建一个Template,如下图 2. ...