<JavaScript深入>for-of、for-in、forEach 和map的区别
JavaScript 深入系列 #9
for...of
语句在可迭代对象(包括Array
,Map
,Set
,String
,TypedArray
,arguments
对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句for...in
语句以任意顺序遍历一个对象的可枚举属性。对于每个不同的属性,语句都会被执行。Array.prototype.forEach()
方法对数组的每个元素执行一次提供的函数。Array.prototype.map()
方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
区别1: for...in 、for...of 可以中断,forEach 、map 不可以中断
var array = ['a', 'b', 'c', 'd', 'e'];
// for...of
for(const value of array) {
// if (value === 'b') countinue; for...of 没有 countinue
if (value === 'e') break;
console.log(value); // a b c d
}
// for...in
for(const value in array) {
// if (value === '1') countinue; for...in 没有 countinue
// typeof value === string
if (value === 4) break; // false
if (value === '4') break; // true
console.log(value); // 0 1 2 3
}
// forEach
array.forEach((value, index) => {
// forEach() 没有办法中止或者跳出循环, 除了抛出一个异常
if (value === 'e') throw 'forEach Error';
console.log(value, index); // a 0 b 1 c 2 d 3
})
// map
array.map((value, index) => {
// map() 没有办法中止或者跳出循环, 除了抛出一个异常
if (value === 'e') throw 'map Error';
console.log(value, index); // a 0 b 1 c 2 d 3
})
区别2: for...of
具有 iterator
接口,for...in
、forEach
、map
没有
var array = ['a', 'b', 'c', 'd', 'e'];
// for...of
for(const value of array) {
// 如果不中断一直循环,卡死
if (array.length > 12) break;
array.push(value);
console.log(value); // a b c d e a b c ...如果一直循环,则一直渲染
}
// for...in
array = ['a', 'b', 'c', 'd', 'e'];
for(const key in array) {
array.push(key);
console.log(key); // 0 1 2 3 4
}
// forEach
array = ['a', 'b', 'c', 'd', 'e'];
array.forEach(value => {
array.push(value);
console.log(value); // a b c d e
})
// map
array = ['a', 'b', 'c', 'd', 'e'];
array.map(value => {
array.push(value);
console.log(value); // a b c d e
})
// 如果是删除数组
// for...of
array = ['a', 'b', 'c', 'd', 'e'];
for(const value of array) {
array.pop();
console.log(value); // a b c
}
// for...in
array = ['a', 'b', 'c', 'd', 'e'];
for(const key in array) {
array.pop();
console.log(key); // 0 1 2
}
// forEach
array = ['a', 'b', 'c', 'd', 'e'];
array.forEach(value => {
array.pop();
console.log('forEach', value); // a b c
})
// map
array = ['a', 'b', 'c', 'd', 'e'];
array.map(value => {
array.pop();
console.log(value); // a b c
})
区别3: for...in
可以遍历 Array
Map
Set
Object
String
, for...of
可以直接遍历 String
Set
,forEach
能遍历 Array
Map
Set
, map
只能遍历 Array
var string = 'abcde';
// for...of
for(const value of string) {
console.log(value); // a b c d e
}
// for...in
for(const key in string) {
console.log(key); // 0 1 2 3 4
}
var json = {a: 'a', b: 'b', c: 'c', d: 'd', e: 'e'};
// for...in 不需要声明遍历器
for(const key in json) {
console.log(key); // a b c d e
}
// for...of 直接调用会报错,object is not iterable
var keys = Object.keys(json);
json[Symbol.iterator] = keys[Symbol.iterator].bind(keys);
// for...of
for(const value of json) {
console.log(value); // a b c d e
}
var object = function() {
this.keya = 'a';
this.keyb = 'b';
this.keyc = 'c';
}
var newObject = new object();
// for...in 不需要声明遍历器
for(const key in newObject) {
console.log(key); // keya keyb keyc
}
// for...of 直接调用会报错,object is not iterable
var keys = Object.getOwnPropertyNames(newObject);
newObject[Symbol.iterator] = keys[Symbol.iterator].bind(keys);
// for...of
for(const value of newObject) {
console.log(value); // a b c
}
var map = new Map();
扩展
forEach
、map
为什么不能 return
或者 break
跳出循环 (猜测)
Array.prototype.forEach = function(callback) {
for (var i = 0; i < this.length; i++) {
callback(this[i], i, this);
}
};
array = ['a', 'b', 'c', 'd', 'e'];
array.forEach((value, index, _array) => {
// break; function 没有 break
// return; 也只是跳过当前 function
console.log(value);
})
forEach
、map
、for...in
在删除数组的时候为什么没有抛出错误
forEach
遍历的范围在第一次调用callback
前就会确定。调用forEach
后添加到数组中的项不会被callback
访问到。如果已经存在的值被改变,则传递给callback
的值是forEach
遍历到他们那一刻的值。已删除的项不会被遍历到。如果已访问的元素在迭代时被删除了(例如使用shift()
),之后的元素将被跳过 - 摘取自 MSD