while
while(){
//......
}
do-while
do{
//......
}while(){
//......
}
for
for(let i = 0; i < array.length; i++){
//......
}
forEach
// currentValue 当前元素
// index 当前元素的索引值。
// arr 当前元素所属的数组对象。
// thisValue 传递给函数的值一般用 "this" 值。如果这个参数为空, "undefined" 会传递给 "this" 值
objArr.forEach(function(currentValue, index, arr){
console.log(value);
}, thisValue);
// IE 8及更早版本不支持
// 1、用 forEach 遍历数组的话,不能中断循环(使用 break 或者 continue)
// 2、只能使用 return 中断本次循环,不能中断整个循环
// 3、如果要提前终止整个循环,必须把 forEach() 方法放在一个 try 块中,
// 并能抛出一个异常。如果 forEach()调用的函数抛出 foreach.break 异常,循环会提前终止
function foreach(a, f, t){
try {
a.forEach(f,t)
}catch(e){
if(e === foreach.break)return;
else throw e;
}
}
foreach.break = new Error("StopIteration");
1、不支持处理异步函数
2、无法捕获异步函数中的错误
3、除了抛出异常之外,没有办法中止或跳出 forEach() 循环
4、forEach 删除自己的元素,索引无法重置
5、this 指向问题
6、forEach 的性能低于 for 循环
7、将跳过已删除或未初始化的项目
8、使用 forEach 不会改变原来的数组
9、forEach 在循环开始前就已经确定循环次数,所以在循环体中增加数组长度,不会改变循环次数,
但是如果在循环体中删除数组某个元素,会改变循环次数
forEach 还有其他问题请参考:https://zhuanlan.zhihu.com/p/614624783?utm_id=0
// forEach 实现原理
Array.prototype.customForEach = function (callback) {
// 检查 callback 是不是函数
if(typeof callback !== 'function') {
throw new TypeError('callback must be a function');
}
for (let i = 0; i < this.length; i++) {
if(i in this){
// 执行 callback 函数,并传入三个参数:当前元素,索引,原数组
callback.call(this[i], i, this);
}
}
}
let list = [1, 2, 3, 4, 5];
list.customForEach((item, i, list) => {
console.log(item, i, list)
})
# 看 forEach 实现原理,也就知道了为什么它不能跳出循环了
for-in
// 所有浏览器都支持
for-in 语句用于遍历对象或者数组的属性(键名)
let es6 = {
edition: 6,
committee: "TC39",
standard: "ECMA-262"
};
for (let i in es6) {
console.log(i); // edition committee standard
console.log(es6[i]); // 6 TC39 ECMA-262
}
let objArr = [ 'a', 'b', 'c' ];
for(let i in objArr){
console.log(i) // 0 1 2
console.log(objArr[i]) // a b c
}
`for-in 循环实际是为循环 可枚举的(enumerable)对象而设计的`
**** 数组上不建议使用 for-in 循环 ****
遍历数组时可能会出现的问题:
1.index 值是字符串(String)类型,可能无意间进行字符串的计算 “2” + 1 = “21” 等,所以不能直接进行几何运算
2.循环不仅会遍历数组元素,还会遍历对象或者数组的原型上的值和手动添加的其他自定义添加的属性,
如 objArr 上面包含自定义属性,objArr.name 那这次循环中也会出现此 name 属性
for (const key in obj) {
if (obj.hasOwnProperty(key)) { // 确保只枚举对象自身的属性
// 安全的操作
console.log(key);
}
}
3.某些情况下,遍历数组元素的顺序可能是随机的
for-in 循环对象:i 值是对象的键名
for-in 循环数组:i 值是数组的索引
for-of
// currentValue 必须。当前元素的值
for(let currentValue of objArr){
console.log(currentValue)
}
JavaScript6 里引入了一种新的循环方法,它就是 for-of 循环,它既比传统的 for 循环简洁,同时弥补了 forEach 和 for-in 循环的短板
如果循环普通对象,会报错 // TypeError: es6[Symbol.iterator] is not a function 或者 // Uncaught TypeError: es6 is not iterable
解决方法是,使用 Object.keys 方法将对象的键名生成一个数组,然后遍历这个数组
for (let key of Object.keys(someObject)) {
console.log(key + ': ' + someObject[key]);
}
如果使用 for of 想要获取当前索引值
var arr = [ 'a', 'b', 'c' ];
for( let [ index, currentValue ] of new Map( arr.map( ( item, i ) => [ i, item ] ) ) ) {
console.log(index, currentValue);
}
或者
for( let [ index, currentValue ] of arr.entries() ) {
console.log(index, currentValue);
}
`for-of 可以使用 break、continue 、return 退出循环`
`for-of 主要遍历 可迭代对象(iterable)`
for-of 可以循环遍历很多东西
1、循环一个数组(Array)
2、循环一个字符串
3、循环一个类型化的数组(TypedArray)
4、循环一个 Map
5、循环一个 Set
6、循环一个 DOM collection(节点)
7、循环一个拥有 enumerable 属性的对象
8、循环一个生成器(generators)
map
map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
map() 方法按照原始数组元素顺序依次处理元素。
注意: map() 不会对空数组进行检测。
注意: map() 不会改变原始数组。
注意: IE 8 及更早版本不支持。
"map() 不会对空数组进行检测" 的意思
这意味着,如果传递给 map() 的数组为空,它不会执行任何操作,也不会抛出异常或错误。map() 方法只是返回一个空的数组。
换句话说,map() 不会对空数组进行任何特殊的检查,它只会简单地返回一个新数组。
// currentValue 必须。当前元素的值
// index 可选。当前元素的索引值
// arr 可选。当前元素属于的数组对象
// thisValue 对象作为该执行回调时使用,传递给函数,用作 "this" 的值。如果省略了 thisValue,或者传入 null、undefined,那么回调函数的 this 为全局对象。
array.map(function(currentValue, index, arr), thisValue)
map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let newArr = arr.map(item => item * 2);
console.log(newArr) // [2, 4, 6, 8, 10, 12, 14, 16, 18]
filter
filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
注意: filter() 不会对空数组进行检测。
注意: filter() 不会改变原始数组。
注意:IE 8 及更早版本不支持。
array.filter(function(currentValue, index, arr), thisValue)
var ages = [32, 33, 16, 40];
let newAges = ages.filter(function(currentValue){
return currentValue >= 18;
})
console.log(newAges) // [32, 33, 40]
// 移除数组中所有的 ”false“ 类型元素
let b = a.filter(Boolean)
// 等同于
let b = a.filter(function(x) { return Boolean(x); })
find、findIndex
find() 方法返回通过测试(函数内判断)的数组的第一个元素的值
find() 方法为数组中的每个元素都调用一次函数执行
当数组中的元素在测试条件时返回 true 时, find() 返回符合条件的元素,之后的值不会再调用执行函数
如果没有符合条件的元素返回 undefined
注意: find() 对于空数组,函数是不会执行的。
注意: find() 并没有改变数组的原始值。
注意: IE 11 及更早版本不支持 find() 方法。
array.find(function(currentValue, index, arr),thisValue)
const ages = [3, 10, 18, 20];
const hasFind = ages.find(i => i >= 18);
console.log(hasFind); // 18
findIndex() 方法返回传入一个测试条件(函数)符合条件的数组第一个元素位置
findIndex() 方法为数组中的每个元素都调用一次函数执行
当数组中的元素在测试条件时返回 true 时, findIndex() 返回符合条件的元素的索引位置,之后的值不会再调用执行函数
如果没有符合条件的元素返回 -1
注意: findIndex() 对于空数组,函数是不会执行的。
注意: findIndex() 并没有改变数组的原始值。
注意: IE 11 及更早版本不支持 findIndex() 方法。
array.findIndex(function(currentValue, index, arr), thisValue)
const ages = [3, 10, 18, 20];
const hasFindindex = ages.findIndex(i => i >= 18);
console.log(hasFindindex); // 2
some、every
some() 方法用于检测数组中的元素是否满足指定条件(函数提供)。
some() 方法会依次执行数组的每个元素:
如果有一个元素满足条件,则表达式返回 true , 剩余的元素不会再执行检测。
如果没有满足条件的元素,则返回 false。
注意: some() 不会对空数组进行检测。
注意: some() 不会改变原始数组。
注意: IE 8 及更早版本不支持。
var resSome = array.some(function(currentValue, index, arr),thisValue)
const numbers = [1, 2, 3, 4, 5];
const hasEven = numbers.some(i => i == 3);
console.log(hasEven); // true
every() 方法用于检测数组所有元素是否都符合指定条件(通过函数提供)。
every() 方法使用指定函数检测数组中的所有元素:
如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且剩余的元素不会再进行检测。
如果所有元素都满足条件,则返回 true。
注意: every() 不会对空数组进行检测。
注意: every() 不会改变原始数组。
注意: IE 8 及更早版本不支持
var resEvery = array.every(function(currentValue, index, arr), thisValue)
const numbers = [1, 2, 3, 4, 5];
const hasEven = numbers.every(i => i <= 4);
console.log(hasEven); // false
reduce、reduceRight
reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
reduce() 可以作为一个高阶函数,用于函数的 compose。
注意: reduce() 对于空数组是不会执行回调函数的。
注意: IE 8 及更早版本不支持。
// total 必需。initialValue 的初始值, 或者计算结束后的返回值
// currentValue 必需。当前元素
// currentIndex 可选。当前元素的索引
// arr 可选。当前元素所属的数组对象
// initialValue 可选。传递给函数的初始值
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
let arr = [1, 2, 3];
let ad = arr.reduce(function(i, j){
return i + j;
})
reduceRight 和 reduce 相反,是从右到左
var arr = [1, 2, 3, 4];
var sum = arr.reduce(function(prev, cur, index, arr) {
console.log(prev, cur, index);
return prev + cur;
})
console.log(arr, sum);
上面的例子索引是从 1 开始的,第一次的 prev 的值是数组的第一个值。数组长度是 4,但是 reduce 函数循环 3次
var arr = [1, 2, 3, 4];
var sum = arr.reduce(function(prev, cur, index, arr) {
console.log(prev, cur, index);
return prev + cur;
}, 0);
console.log(arr, sum);
如果没有提供 initialValue,reduce 会从索引 1 的地方开始执行 callback 方法,跳过第一个索引
如果提供 initialValue,reduce 会从索引 0 的地方开始,reduce 函数循环 4次
求和
var arr = [1, 2, 3, 4];
var sum = arr.reduce((x, y) => x + y)
console.log(sum); // 10
求乘积
var arr = [1, 2, 3, 4];
var mul = arr.reduce((x, y) => x * y)
console.log(mul); // 24
计算数组中每个元素出现的次数
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
let nameNum = names.reduce((pre, cur) => {
if(cur in pre){
pre[cur]++
}else{
pre[cur] = 1;
}
return pre
}, {});
console.log(nameNum); // { Alice: 2, Bob: 1, Tiff: 1, Bruce: 1 }
数组去重
let arr = [1, 2, 3, 4, 4, 1];
let newArr = arr.reduce((pre, cur) => {
if(!pre.includes(cur)){
return pre.concat(cur);
}else{
return pre;
}
}, []);
console.log(newArr); // [1, 2, 3, 4]
将二维数组转化为一维
let arr = [[0, 1], [2, 3], [4, 5]]
let newArr = arr.reduce((pre, cur) => {
return pre.concat(cur)
},[])
console.log(newArr); // [0, 1, 2, 3, 4, 5]
将多维数组转化为一维
let arr = [[0, 1], [2, 3], [4, [5, 6, 7]]]
const newArr = function(arr){
return arr.reduce((pre, cur) => pre.concat(Array.isArray(cur) ? newArr(cur) : cur), [])
}
console.log(newArr(arr)); // [0, 1, 2, 3, 4, 5, 6, 7]
对象里的属性求和
var result = [
{
subject: 'math',
score: 10
},
{
subject: 'chinese',
score: 20
},
{
subject: 'english',
score: 30
}
];
var sum = result.reduce(function(prev, cur) {
return cur.score + prev;
}, 0);
console.log(sum) // 60
数组转对象
const list = [
{ name: 'yzw', area: 'gz', age: 27, sex: '男' },
{ name: 'tyj', area: 'sz', age: 24, sex: '女' }
];
const map = list.reduce((prev, cur) => {
const { name, ...rest } = cur;
prev[name] = rest;
return prev;
}, {});
console.log(map);
// {
// tyj: { area: 'sz', age: 24, sex: '女' }
// yzw: { area: 'gz', age: 27, sex: '男' }
// }