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