for循环
for in
for of
forEach
map
reduce
for循环
break\continue\return
for in
for in 和 for 循环的区别:
1、for-in 语句以原始插入顺序迭代对象的可枚举属性。for-in会把继承链的对象属性都会遍历一遍
2、for key in arr 是索引值,索引值不是数字类型,而是string。手动设置arr.name = ‘1’; for in 也可以打印出来
遍历的属性key 是迭代元素的属性值,而不是value值
const arr = []; arr[0]=0; arr[2]=2; arr[4]=4;# for 循环: 打印结果: 0, undefined, 2,undefined,4for (var i = 0, len = arr.length; i < len; i++){console.log(arr[i]);}# for in 只打印出遍历对象的可枚举属性# 打印结果: 0, 2,4for (var key in arr){console.log(arr[i]);}
for in特点:
- “索引值”是String类型
- 循环出的值不一定是按顺序的
- 遍历对象可枚举的属性
- 可遍历出对象原型中的属性
结论:for in 更适合遍历对象,且遍历对象时配合 arr.hasOwnProperty(key) 使用
forEach
for of\ for in \ for \forEach
//语法 [].forEach(function(value, index, array){ // do some })
callback参数
- value(当前值)—-数组中正在处理的当前元素
- index(索引) —-数组中正在处理的当前元素的索引
- array —-正在应用forEach()数组
优点:
1、不用重新声明index和遍历的元素
2、已被删除 或 从未赋值的项 会被跳过 (注:从未被赋值 不包括值本身为undefined 、null的项
var array = [1, 2, 3];delete array[1];console.log(array); //===>[1, undefined × 1, 3]array.forEach(function(value){console.log(value);}) //===>1, 3
优点:
3、不会遍历到数组原型链上的属性
4、index是Number 类型
var arr = [];arr[0] = "a";arr[3] = "b";arr[10] = "c";arr.name = "Hello world";arr.forEach(function(data, index, array) {console.log(data);// 0 3 10});
弊端:
0、forEach 里面return ,不是整个函数的return; (因为forEach本质是回调函数);使用return时,效果和在for循环中使用continue一致
1、没有办法跳出或终止 forEach 循环,break,continue不会跳出循环,
2、如果在迭代中删除了元素,之后的元素会被跳过。
for of
for…of语句在可迭代对象(包括 Array, Map, Set, String, TypedArray,arguments 对象等等)上创建一个迭代循环,对每个不同属性的属性值,调用一个自定义的有执行语句的迭代挂钩
特点
- 比普通for简洁
- 比forEach 灵活,支持break, continue, return
- 比for..in 作用更大, 除了可以遍历数组,还可以以遍历遍历其它集合,如字符串、Map 和 Set 对象、DO 集合等
for…of与for…in的区别
- for…in 遍历每一个属性名称key,而 for…of遍历每一个属性值value:
- for…in循环会遍历一个object所有的可枚举属性
- for…of语法是为各种collection对象专门定制的,并不适用于所有的object.它会以这种方式迭代出任何拥有[Symbol.iterator] 属性的collection对象的每个元素
Object.prototype.objCustom = function () {};Array.prototype.arrCustom = function () {};let iterable = [3, 5, 7];iterable.foo = "hello";for (let i in iterable) {console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom"}for (let i of iterable) {console.log(i); // logs 3, 5, 7}
map
map方法会给原数组中的每个元素都按顺序调用一次callback函数。callback每次执行后的返回值包括 undefined)组合起来形成一个新数组。callback函数只会在有值的索引上被调用;那些从来没被赋过值或者使用delete删除的索引则不会被调用。
map一般用于,对原数组新增或修改某属性,然后得到新的数组
const arr2 = arr.map(item => {item.total = item.price * item.count;return item;})
那些从来没被赋过值或者使用delete删除的索引则不会被调用:
Array(10).map(function(){return "A"})// => [undefined * 10]
题外话:
一个经典的面试题:[1,2,3].map(parseInt)
请解释下面代码的执行结果
console.log([10, 11, 12].map(parseInt)); // [1, NaN, NaN]console.log([1, 2, 3].map(parseFloat)); // [1, 2, 3]console.log([1.1, 2.2, 3.3].map(parseInt)); // [1, NaN, NaN]console.log([1.1, 2.2, 3.3].map(parseFloat)); // [1.1, 2.2, 3.3]
parseInt:parseInt(string [, radix]) 接受两个参数 将字符串解析成radix进制的数字 如 parseInt(‘110’, 2) // 2进制的110表示10进制的6注意的点:> 1、如果传入第一个参数非string会调用string转换为字符 2、该函数的返回值NAN的情况: radix < 2 or string转换为数字失败、 3、radix=0时,按十进制处理 parseFloat:parseFloat(value) 将字符串解析成浮点数 只接受一个参数
[1, 2, 3].map(parseInt); // [1, 2, 3]// ==> 实际上解析为// parseInt(1, 0) == 1 // 无0进制 直接转为十进制// parseInt(2, 1) == NAN // 直接返回NAN// parseInt(3, 2) == NAN // 2进制只能用01表示 这里出现了3 所以NAN
reduce
reduce() 方法接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始合并,最终为一个值。 [].reduce(callback,[initialValue])
callback 被调用时传入四个参数: callback(accum, cur, index, arr)
- 上一次调用回调返回的值previousValue
- 当前迭代元素的值 currentValue
- 元素的索引
- 调用reduce的数组
initialValue ===>作为第一次调用 callback 的第一个参数。
回调函数第一次执行时,previousValue 和 currentValue 的取值有两种情况。
- 如果 initialValue 在调用 reduce 时被提供,那么第一个 previousValue 等于 initialValue ,并且currentValue 等于数组中的第一个值;
- 如果initialValue 未被提供,那么previousValue 等于数组中的第一个值,currentValue等于数组中的第二个值。
- 如果数组为空并且没有提供initialValue, 会报错。
- 如果数组仅有一个元素(无论位置如何)并且没有提供initialValue,或者有提供initialValue但是数组为空,那么此唯一值将被返回并且callback不会被执行。
reduce的精华所在是将累计器逐个作用于数组成员上,把上一次输出的值作为下一次输入的值。
迭代应用:
1、reduce实现map、filter的功能:
const arr = [0, 1, 2, 3];// 代替map:[0, 2, 4, 6]const a = arr.map(v => v * 2);const b = arr.reduce((accurmArr, v) => [...accurmArr, v * 2], []);// 代替filter:[2, 3]const c = arr.filter(v => v > 1);const d = arr.reduce((accurmArr, v) => v > 1 ? [...accurmArr, v] : accurmArr, []);
2、reduce数据统计
# 统计出各个数的出现频率
const arr = [0, 1, 1, 2, 2, 2];
console.log(getCount(arr)); // { 0: 1, 1: 2, 2: 3 }
# way1: 普通迭代
function getCount(arr) {
let hash = {};
arr.forEach(item => {
hash[item] = (hash[item] || 0) + 1;
});
return hash;
}
# way2: reduce
function getCount(arr) {
return arr.reduce((accurmHash, cur) => {
accurmHash[cur] = (accurmHash[cur] || 0) + 1;
return accurmHash;
}, {});
}
3、reduce累加
# 计算数组的累加
const arr = [0, 1, 2, 3, 4, 5];
console.log(getAccumulation(arr)); // 15
# 普通迭代
function getAccumulation(arr) {
let res = 0;
arr.forEach(item => res += item);
return res;
}
# reduce
function getAccumulation(arr) {
return arr.reduce((acc, item) => acc + item, 0);
}
