[Effective JavaScript 笔记]第5章:数组和字典--个人总结
前言
这节里其实一直都在讨论对象这个在js中的万能的数据结构。对象可以表式为多种的形式,表示为字典和数组之间的区别。更多的我觉得这章讨论多的是一些对应实现功能的相关操作,有可能出现的bug以及如何避免来修复这些bug。比如下面会说到的for...in枚举属性的操作,可能因为对原型的一些操作,最终造成数据对象的操作的破坏。对于属性顺序有要求的如何处理,对类数组如何处理等。下面再一起一条一条回顾一下,这章里的主要内容。我觉得没必要讲的会一语带过,相比前面的几章,个人觉得这章的内容重点很少,注意几点就好,有几条只是强调一个知识点,有点繁琐。
第43条:使用Object的直接实例构造轻量级的字典
个人总结
这条里主要是强调在使用对象做为字典这种数据结构时,使用Object的直接实例来完成。
语法如下:
var obj=new Object();
//或
var obj1={};
上面这样做的好处是在列举对象的属性时,按字典的说法就是键值key的时候,可以通过for...in循环来处理。
自定义字典类对象
如果这里用的是自定义的对象在使用for...in循环时,把添加到原型对象中的方法也做为key值返回了,和最初的程序需求不相符。
数组对象字典
数组对象也存在着和自定义类对象相的问题,有许多的ES5的数组方法,在有些环境中无法支持。会使用polyfill来对相应方法进行添加。最后也会污染到for...in循环。
基于上面的两种方式可能出现的问题。使用对象的直接实例可以把可能出现的问题控制在可控的区域。
提示
使用对象字面量构建轻量级字典
轻量级字典应该是Object.prototype的直接子类,以使for...in循环免受原型污染
第44条:使用null原型以防止原型污染
个人总结
基于上一条讲的,for...in枚举属性的问题,可以使用ES5中的Object.create方法,创建一个原型为null的对象。语法如下:
var obj=Object.create(null);
对于不支持Object.create方法的环境,只能使用非标准属性__proto__来兼容。
var o={__proto__:null};
o.instanceof Object;//false
可能有人会想下面的这种形式来解决相同的问题。但直接使用C.prototype=null,并不能完成。
function C(){}
C.prototype=null;
var c=new C();
Object.getPrototypeOf(c) === null;//false
使用null为原型来防止原型污染,使用技术如下:
在开发时优先使用ES5的Object.create(null)
在不支持ES5但支持非标准的__proto__属性的,使用obj.__proto__=null;
其他环境提示无法完成相关的功能
提示
在ES5环境中,使用Object.create(null)创建的自由原型的空对象是不太容易被污染的
在一些较老环境中,考虑使用{__proto__:null}
__proto__既不标准,也不可移植,并且可能未来不再支持
不要使用__proto__名作字典的key,因为一些环境将其作为特殊的属性对待
第45条:使用hasOwnProperty方法以避免原型污染
个人总结
第43,44条中讲到for...in枚举属性时,一直受到原型对象污染,无法只获取对象自身的属性。可以使用hasOwnProperty方法来对自身属性进行判断。hasOwnProperty本身是Object.prototype中的方法。所有对象都会继续这个方法。
对象直接调用hasOwnProperty方法
直接使用当前对象调用hasOwnProperty方法,有一个问题就是当前的对象或原型链中没有原型对象对这个方法进行重新的定义,才能保重代码的正确性。
使用函数的call方法对Object.prototype.hasOwnProperty方法进行处理
var hasOwn=Object.prototype.hasOwnProperty;
hasOwn.call(obj1);
可以保证hasOwnProperty在判断属性时的正确性。可以为需要的对象,把以上的判断封装在一个方法中方便调用。
对特殊的属性__proto__进行处理
使用记录状态的方法,来对非标准属性,进行代码兼容。防止环境不同,造成代码功能受到破坏。对于非定义的默认为false,详细代码到文章查看。
提示
使用hasOwnProperty方法避免原型污染
使用词法作用域和call方法避免覆盖hasOwnProperty方法
考虑在封装hasOwnProperty测试样板代码的类中实现字典操作
使用字典类避免将“__proto__”作为key来使用
第46条:使用数组而不要使用字典来存储有序集合
个人总结
因为字典的属性的读取是依赖于for...in循环的,而for...in循环在标准库中并没有规定相关属性的顺序,所以无法确切地知道属性输出的顺序。如果对于属性顺序的依赖性强,那么就不能使用字典来存储数据。而用数组存储,可以使用for循环,严格按照索引的顺序对数据进行处理。
本节有意思的是提到了浮点数的计算问题,浮点数的计算结果依赖于计算顺序,所以不能使用字典的形式也就是for...in循环的形式对各项进行加操作。解决办法是通过把浮点数转化为整数,然后把计算结果再转化为浮点数的方法,来解耦顺序依赖。
提示
使用for...in循环来枚举对象的属性应当与顺序无关
如果聚集运算字典中的数据,确保聚集操作与顺序无关
使用数组而不是字典来存储有序集合
第47条:绝不要在Object.prototype中增加可枚举的属性
个人总结
还是和for...in循环有关,因为Object是所有js对象的根对象(Object.create(null)创建 的除外)。任何对象都是继承自Object.prototype对象的。对Object.prototype的操作,会影响到所有对象。如果非要添加方法或属性,可以使用Object.defineProperty方法,把属性或方法设置为不可枚举的。这样可以避免污染原型对象。
提示
避免在Object.prototype中增加属性
考虑编写一个函数代替Object.prototype中的方法
如果确实需要在Object.prototype中增加属性,使用ES5中的Object.defineProperty方法将它们定义为不可枚举的属性。
第48条:避免在枚举期间修改对象
个人总结
还是和for...in循环有关,之前上面的已经讲过,for...in循环无法保证枚举属性的顺序。所以在修改对象属性时,可能枚举的是新的属性值,有可能是枚举的是旧的属性值。标准规定:如果被枚举的对象在枚举期间添加了新的属性,那么在枚举期间并不能保证新添加的属性能访问。
避免使用for...in循环执行这样的操作,使用其它替代的方案。比如自己管理循环控制,使用while循环来对对象进行相关操作。
本条中有相关有向图的遍历和查找相关的代码,到具体文章查看。
提示
当使用for...in循环枚举一个对象的属性时,确保不要修改对象
当迭代一个对象时,如果该对象的内容可能会在循环期间被改变,应用使用while循环或经典for循环来代替for...in循环
为了在不断变化的数据结构中能够预测枚举,考虑使用一个有序的数据结构,例如数组,而不要使用字典对象
第49条:数组迭代要优先使用for循环而不是for...in循环
个人总结
for
for循环可以保证代码的执行过程的顺序,及可以根据索引去取确定的值。不会受其它因素的影响。
小知识点
对数组长度的存储,可以减少每次对数组长度的访问,提高循环的效率。
for(var i=0;i < arr.length;i++){}
其中var i=0;中执行一次,i < arr.length每次代码块执行前执行,i++代码块执行后执行。所以这里arr.length每一次都会去获取,使用下面这种方式更好:
for(var i=0,n=arr.length;i < n;i++){}
for...in
for...in循环可能会被原型链中的对象方法污染,无法保证其代码的正确性。
对比一下:
for循环清晰可控结果可预期
for...in循环不确定性强,容易被污染,顺序不可控
提示
迭代数组的索引属性应当总是使用for循环而不是for...in循环
考虑在循环之前将数组的长度存储在一个局部变量中以以避免重新计算数组长度
第50条:迭代方法优于循环
个人总结
得益于ES5里提供了功能强大的,众多的数组迭代方法,使得数组的处理更方便。主要包括filter,forEach,every,some,map等方法,具体详细可参阅对应的小节文章。
在使用for循环的时候,往往在边界条件设定错误,导致数组的溢出,或数组元素没被遍历的情况。对于这些问题都要小心去调试和对待,有时代码抽象层次高了之后,问题不容易被发现。
使用迭代方法,不用考虑边界条件的问题。主要考虑得是各个迭代方法的用法及它们之间的区别。利用不同的特性来完成个性化的需求。
通过猴子补丁给数组添加一些的新的迭代方法,比如这节里讲的takeWhile方法。
主要是功能,是提取出满足函数的数组的前几个元素。具体代码到文章里查看。
提示
使用迭代方法替换for循环使得代码更可读,并且避免了重复循环控制逻辑
使用自定义的迭代函数来抽象未被标准库支持的常见循环模式
在需要提前终止的情况下,仍然推荐使用传统的for循环。some和every方法也可以用于提前退出
第51条:在类数组对象上利用通用的数组方法
个人总结
类数组对象中,大家经常使用的jQuery对象就是一个类数组的存在。也可以用这里的方法对它进行操作。如使用
[].slice.call($('a')).forEach(function(a){
a.style.display='none';
})
这里只是举个例子,jquery里使用迭代方法的地方很多。
可以看看jquery里是怎样去完成类数组对象的构造的。主要是makeArray方法
//以下代码来自1.7.1版本
function makeArray(array,results){
var ret = results || [];
if ( array != null ) {
var type = jQuery.type( array );//这里只是一个类型的判断
if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
push.call( ret, array );
} else {
jQuery.merge( ret, array );//这里是主要的
}
}
return ret;
}
//merge方法
function merge( first, second ) {
var i = first.length,//并不要求第一个是数组对象,有.length属性就成
j = 0;
if ( typeof second.length === "number" ) {//主要关注这里
for ( var l = second.length; j < l; j++ ) {
first[ i++ ] = second[ j ];
}
} else {
while ( second[j] !== undefined ) {
first[ i++ ] = second[ j++ ];
}
}
first.length = i;
return first;
}
可以看出上面的代码jquery本身是一个对象,并没有元素数组。而是通过一些方法获取到选择器对就的页面元素的数组后,利用merge方法把这些数组元素加到jquery对象上,并设置其length属性的长度,从而把jquery对象变成一个类数组了。
通过这个也可以引出类数组的满足的两条契约:
具有一个范围在0到2^32-1的整形length属性
length属性大于该对象的最大索引。索引是一个范围在0到2^32-1的整数,它的字符串表示是该对象中的一个key
提示
对于类数组对象,通过提取方法对象并使用其call方法来复用通用的Array方法
任意一个具有索引属性和恰当length属性的对象都可以使用通用的Array方法
第52条:数组字面量优于数组构造函数
个人总结
这个没什么好说的,就是各种对应的数组,对象,函数等有构造函数,又有字面量方式的,使用字面量的方式更好。
防止构造函数命名被覆盖,无法完成正确功能。防止由于参数传递不同的值造成了不一样的结果。就是能用字面量就用字面量
提示
如果数组构造函数的第一个参数是数字则数组的构造函数行为是不同的
使用数组字面量替代数组构造函数
总结
这一章前半的条目,都是绕怎么解决对象字典的属性列举问题。列举属性使用的for...in循环的各种问题,原型污染,顺序不确定,枚举过程中操作的响应问题。后半主要讨论数组的相关操作问题,迭代方法优于循环,字面量优于构造函数,类数组的处理方法。通过这章学习,可以很明确地区分字典对象和数组之间的联系和区别,同时它们也是两种不同的数据结构。字典是无序,散列的键值对;数组是有序,索引的数据集合。
[Effective JavaScript 笔记]第5章:数组和字典--个人总结的更多相关文章
- [Effective JavaScript 笔记]第3章:使用函数--个人总结
前言 这一章把平时会用到,但不会深究的知识点,分开细化地讲解了.里面很多内容在高3等基础内容里,也有很多讲到.但由于本身书籍的篇幅较大,很容易忽视对应的小知识点.这章里的许多小提示都很有帮助,特别是在 ...
- [Effective JavaScript 笔记]第6章:库和API设计--个人总结
前言 又到了一章的总结,这章里的内容.是把我从一个代码的使用者,如何换位成一个代码的编写者.如何让别人用自己的代码更容易,不用去注意太多的无用细节,不用记住冗长的函数名.在使用API时怎样避免使用者会 ...
- [Effective JavaScript 笔记]第7章:并发--个人总结
前言 这一章的内容学到了事件队列和异步的API.js只是运行在其他应用程序的脚本语言.js即依赖于应用程序,也独立与应用程序.可以使它可以在多平台,多种环境上运行.ECMAScript标准中没有关于并 ...
- [Effective JavaScript 笔记] 第1章:让自己习惯javascript小结
在这里整理一下,每条对应的提示 第1条:了解使用的js版本 确定应用程序支持的js的版本(浏览器也是应用程序噢) 确保使用的js特性是应用程序支持的(要不写了也运行不了) 总是在严格模式下编写和测试代 ...
- [Effective JavaScript 笔记]第2章:变量作用域--个人总结
前言 第二章主要讲解各种变量作用域,通过这章的学习,接触到了很多之前没有接触过的东西,比如不经常用到的eval,命名函数表达式,with语句块等,下面是一个列表,我对各节的一点点个人总结,很多都是自己 ...
- [Effective JavaScript 笔记]第4章:对象和原型--个人总结
前言 对象是js中的基本数据结构.对象在js语言编码中也随处可见,比如经常会用到的函数,也是一个Function构造函数,Function.prototype原型对象.每当声明一个函数时,都会继承Fu ...
- [Effective JavaScript 笔记]全书总结
这本书中就像它前言中说的那样,这本书不是给初学者的.需要一定的基础,而且有一定的编码实践,才能很好的理解书里讲到的内容.学习一门编程语言,需要熟悉它的语法.形式和结构,这样才会编写合法的.符合语义的. ...
- [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 ...
随机推荐
- CodeIgniter框架中关于URL(index.php)的那些事
最近,在做自己的个人网站时,采用了轻量级的php框架CodeIgniter.乍一看上去,代码清晰简洁,MVC模型非常容易维护.开发时我采用的工具是Netbeans IDE 8.0,当然,本文的内容和开 ...
- grootJS ui控件定义
index13.html <html><head> <title>ui控件定义</title> <script src="jquery- ...
- canvas粒子demo
之前在codepen上看到了类似的效果,于是自己也使用coffee-script写了个相似的demo 效果:http://whxaxes.github.io/canvas-test/src/Parti ...
- [转载]使用HttpWebRequest进行请求时发生错误:基础连接已关闭,发送时发生错误处理
转载,原文来自 http://blog.csdn.net/hawksoft/article/details/21776009 最近调试原来的微信模拟登陆时发生了“基础连接已关闭,发送时发生错误”的错误 ...
- 我的第二个app上线:术购管家
忙了两周写完的app,终于发布了,可是等上线竟然等了两周多,今天终于上线了,一路顺畅,没有被打回过...
- Mysql-proxy中的lua脚本编程(一)
在为mysql-proxy编写lua脚步的时候,需要知道一下几个入口函数,通过这几个入口函数我们可以控制mysql-proxy的一些行为. connect_server() 当代理服 ...
- (转载)Go语言开发环境配置
一.我为什么要学习go语言 当今已经是移动和云计算时代,Go出现在了工业向云计算转型的时刻,简单.高效.内 置并发原语和现代的标准库让Go语言尤其适合云端软件开发(毕竟它就是为此而设计的).到2014 ...
- OC基础--内存管理中的@property关键字以及其参数
在上一篇博客中整理的内存管理,管理类的代码量会感觉很大,而且如果对象多的话,感觉到代码有点冗余.下面就介绍Xcode中为我们自动生成内存管理代码的关键字@property 例如:在Person这个类中 ...
- MVC学习Day02之校验
MVC校验有两种方法: 方法一:自己动手写js---------略 方法二: l在View的页面中,首先指定页面强类型@model 类型 l使用Html.***For(model=>model. ...
- JS:采摘自JS精粹
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...