Tips:
由于标准允许JavaScript引擎自由选择顺序,那么如果用字典存储有序数据,就会导致兼容性问题。
Tips:
for...in
循环非常便利,但是容易受到原型污染。如果在Object.prorotype中增加可枚举属性的话,将会导致大多数for...in
循环受到污染。
如果是在是要在Object.prototype上定义属性的话,可以使用如下代码:
Object.defineProperty(Object.prototype, 'allKeys', { value: function(){ var arr = []; for(var key in this){ arr.push(key); } return arr; }, writable: true, enumerable: false, //设置属性为不可枚举 configurable: true });
测试代码:
var obj = {a: 1, b: 2}; console.log(obj.allKeys()); // ['a', 'b']
Tips:
for...in
循环枚举一个对象的属性时,确保不要修改该对象for...in
在大部分编译型语言中,如果在迭代时修改对象属性,是会出现编译错误的。在js中,没有这样的编译机制,但是也尽量保证不要修改迭代对象。
如果在被枚举时添加了新对象,并不一定能保证新添加的对象能被访问到:
var obj = {a: 1, b: 2}; for(var p in obj){ console.log(p); obj[p + '1'] = obj[p] + 1; }
遇到这样的场景,应当使用while和标准的for循环。
for...in
循环Tips:
for...in
循环猜测下面一段代码的结果?
var arr = [5, 6, 8, 10, 9]; var sum = 0; for(var a in arr){ sum += a; } console.log(sum);
要达到正确的结果,那么应该使用for循环
var arr = [5, 6, 8, 10, 9]; var sum = 0; for(var i = 0, len = arr.length; i < len; i++){ sum += arr[i]; } console.log(sum); //38
再看一个比较极端的例子:
var arr = [5, 6, 8, 10, 9]; arr.len = 4; for(var p in arr){ console.log(p); }
这个时候用for...in
,完全是达不到预期效果的
再来看一个对于数组长度缓存的测试代码:
var count = 0; console.time('t1'); while(count < 10000){ var arr = [5, 6, 8, 10, 9]; var sum = 0; count++; for(var i = 0, len = arr.length; i < len; i++){ sum += arr[i]; } } console.timeEnd('t1'); count = 0; console.time('t2'); while(count < 10000){ var arr = [5, 6, 8, 10, 9]; var sum = 0; count++; for(var i = 0; i < arr.length; i++){ sum += arr[i]; } } console.timeEnd('t2');
结果,请自行复制代码执行。。。
Tips:
在使用循环的时候,在确定循环的终止条件时容易引入一些简单的错误:
for(var i = 0; i <= n; i++){} for(var i = 1; i< n; i++){}
比较庆幸的是,闭包是一种为这些模式建立迭代抽象方便的、富有表现力的手法。
我们可以用以下代码来代替:
var arr = [1, 2, 3]; arr.forEach(function(v, i){ console.log(v); });
如果要创建新数组,那么可以用以下方式:
var arr = [1, 2, 3]; var arrNew = []; //方式一 arr.forEach(function(v, i){ arrNew.push(v); }); //方式二 for(var i = 0, len = arr.length; i < len; i++){ arrNew.push(arr[i]); }
为了简化这种普遍操作,ES5中引入了Array.prototype.map方法:
var arr = [1, 2, 3]; var arrNew = arr.map(function(v){ return v; });
同样,如果想提取满足条件的元素,ES5也提供了filter方法:
var arr = [1, 2, 3]; var arrNew = arr.filter(function(v){ return v > 1; }); console.log(arrNew);
在ES5中,针对数组也提供了some和every ,可以用来终止循环,但是实际意义等同于C#的Linq方法All和Any:
var arr = [1, 2, 3]; //数组元素有一个>1就返回true,并终止循环 var b = arr.some(function(a){ return a>1; }); console.log(b); //true //数组元素每个都<3,则返回true,否则返回false,并提前终止循环 b = arr.every(function(a){ return a<3; }); console.log(b); //false