【JavaScript】数组 遍历方法是如何遍历稀疏数组

目录

数组遍历方法总结

1.forEach

2.map

3.for...of / for...in

4.some

5.every

6.filter

7.find

8.findIndex

9.reduce

10.总结


数组遍历方法总结

1.forEach

方法对数组的每个元素执行一次给定的函数

用法:依次向 callback 函数传入三个参数:数组当前值,数组当前项的索引,数组对象

arr.forEach(callback(currentValue [, index [, array]]))

需要注意的是

  1. forEach()在被调用时不会改变原数组,尽管 callback 函数在被调用时可能会改变原数组
  2. forEach()总是返回undefined,而且不可链式调用
  3. 不对未初始化的值进行任何操作(稀疏数组),直接跳过callback函数
let items = [1, 2,, 4]
let num = 0

let temp = items.forEach(ele => {
    console.log(ele)
    num++
})

console.log("num: " + num)
console.log("temp: " + temp)

// 1
// 2
// 4
// num: 3 跳过了未初始化的值,只执行了3次
// temp:undefined

2.map

方法创建一个新数组,其结果是该数组中的每个元素都调用一次提供的函数后的返回值

用法:
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
 // Return element for new_array 
})

注意点:

  1. map在被调用时不会改变原数组,会生成一个新数组返回
  2. 从来没被赋过值不会被调用callback
  3. 当callback没有返回值时,新数组也会保留该项,值为undefined
  4. 当遇到稀疏数组是,map()会跳过空位,但会保留这个值
var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
// roots的值为[1, 2, 3], numbers的值仍为[1, 4, 9]

var items= [1, 2,, 4,];
var filteredNumbers = items.map(function(num, index) {
  if(index < 3) {
     return num;
  }
});
console.log(filteredNumbers) // [1, 2, , undefined]

有个很容易犯的错误,例如:

["1", "2", "3"].map(parseInt);

 期望输出[1, 2, 3] 实际结果是[1, NaN, NaN]

在这里parseInt作为回调函数实际上接收了currentValue,index两个参数

// parseInt(string, radix) -> map(parseInt(value, index))
/* 第一次 (index is 0): */ parseInt("1", 0); // 1     当radix参数为0,parseInt() 会根据十进制
/* 第二次 (index is 1): */ parseInt("2", 1); // NaN  当radix该参数小于 2 或者大于 36 返回NaN
/* 第三次 (index is 2): */ parseInt("3", 2); // NaN  用2进制来解析,应以 0 和 1 开头,所以结果为 NaN


// 解决办法:
function returnInt(element) {
  return parseInt(element, 10);
}

['1', '2', '3'].map(returnInt); // [1, 2, 3]

// 还可以用更简单的方法避免陷阱:
['1', '2', '3'].map(Number); // [1, 2, 3]

3.for...of / for...in

for...of在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句

for...in 以任意顺序遍历一个对象的除Symbol以外的可枚举属性

for...of 与for...in的区别

  1. for...in迭代的顺序不一定按照次序,如果当迭代访问顺序很重要的数组时,最好用整数索引去进行for循环、forEach、for...of
  2. for..in 会返回所有可枚举属性,包括原型链上的属性
  3. for...in循环出的是key,for...of循环出的是value
// for...in 语句以任意顺序迭代对象的可枚举属性。

// for...of 语句遍历可迭代对象定义要迭代的数据。

Object.prototype.objCustom = function() {}; 
Array.prototype.arrCustom = function() {};

let iterable = [3, 5, 7];
iterable.foo = 'hello';

for (let i in iterable) {
  console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom"
}

for (let i in iterable) {
  if (iterable.hasOwnProperty(i)) {
    console.log(i); // 0, 1, 2, "foo"
  }
}

for (let i of iterable) {
  console.log(i); // 3, 5, 7
}

4.some

方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值

注意点:

  1. some不会改变原数组
  2. 空数组调用任何情况都是返回false
  3. 当遇到稀疏数组是,map()会跳过空位不执行回调函数
  4. some遍历的数组长度第一次执行回调时已经确定,所以在callback中添加进数组的值不会被callback访问到,已经被删除的值不会被访问到
function isBiggerThan10(element, index, array) {
  return element > 10;
}

[2, 5, 8, 1, 4].some(isBiggerThan10);  // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true

// 使用箭头函数更简洁的写法
[2, 5, 8, 1, 4].some(x => x > 10);  // false
[12, 5, 8, 1, 4].some(x => x > 10); // true

// 空数组
[].some(x => x < 10) // false

//第一次执行回调已经确定元素的范围,新增的不会被访问到
let item = [1, 2, 5]
let isBiggerThan = item.some(x => {
    item.push(20)
    return x > 10
})
console.log(item) // [1, 2, 5, 20, 20, 20]
console.log(isBiggerThan) // false


// 已经被删除的元素也不会被访问到
var item = [1, 2, 15]
let isBiggerThan = item.some(x => {
	item.pop() // 删除最后一项元素
	return x > 10
})
console.log(item) // [1]
console.log(isBiggerThan) // false

5.every

方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。返回一个布尔值。

注意点:

  1. every不会改变原数组
  2. 遇到稀疏数组,回调函数会直接跳过空位
  3. 同some一样,遍历的数组长度第一次执行回调时已经确定,在callback中添加进数组的值不会被callback访问到,已经被删除的值不会被访问到
  4. 空数组调用任何情况都是返回true
// 空数组
[].every(x => x < 10) // true

// 稀疏数组,跳过未赋值的值
[13,,20].every(x => x > 10) // true

6.filter

方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。

注意点:

  1. filter不会改变原数组,只返回过滤后的新数组
  2. callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用
  3. 同some、every一样,遍历的数组长度第一次执行回调时已经确定,在callback中添加进数组的值不会被callback访问到,已经被删除的值不会被访问到
function isBigEnough(element) {
  return element >= 10;
}
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered is [12, 130, 44] 

7.find

方法返回数组中满足提供的测试函数的第一个元素的值。否则返回undefined

注意点:

  1. find方法不会改变原数组
  2. 当稀疏数组调用find方法时,回调函数不会跳过没有值的索引,这说明find方法效率要低于那些只遍历有值索引的方法
  3. 第一次调用就确定索引范围,添加到数组的新元素将不会被callback访问到,被删除的值仍会被访问到(undefined)
// 稀疏数组,不会跳过
let num = 0;
let hasRight [1,2,3,,5].find(x => {
    console.log(num) // 0 1 2 3 4
    num++
    return x > 5
})
console.log(hasRight) // undefined
 

8.findIndex

方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。

注意点:

  1. findIndex不会改变原数组
  2. 不会跳过稀疏数值中未初始化值的索引
  3. 第一次调用就确定索引范围,添加到数组的新元素将不会被callback访问到,被删除的值仍会被访问到
const array1 = [5, 12, 8, 130, 44];

const isLargeNumber = array1.findIndex(element => element > 13); // 3

9.reduce

方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。

用法:reduce接受两个参数,分别是callback(reducer)、初始值initialValue(可选)

  1. reducer接受4个参数,分别是Accumulator累计器、CurrentValue 当前值、CurrentIndex 当前索引、SourceArray 原数组
  2. initialValue,作为第一次调用 callback函数时的第一个参数的值,如果不传默认值为数组的第一个元素

注意点:

  1. reduce不会改变原数组
  2. reduce会跳过稀疏数值中未初始化值的索引
  3. 如果数组为空,且没有提供初始值,会抛出TypeError
  4. 如果数组只有一个元素,且没有初始值,或者提供了初始值但数组为空,reduce不执行回调直接返回唯一值
  5. 如果没有提供初始值,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供初始值,从索引0开始。
  6. 如要累加对象数组的属性,必须提供初始值
[0, 1, 2, 3, 4].reduce((prev, curr) => prev + curr ); // 10

// 提供初始值
[0, 1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => { 
    return accumulator + currentValue; 
}, 10 ); // 20

// 箭头函数
[ 0, 1, 2, 3 ].reduce(
  ( acc, cur ) => acc + cur,
  0
);

// 空数组
[].reduce((prev, curr) => prev + curr ); // TypeError

// 提供了初始值
[].reduce((prev, curr) => prev + curr, 20 ); // 20

// 数组长度为1
[15].reduce((prev, curr) => prev + curr ); // 15

//累加对象数组
var initialValue = 0;
var sum = [{x: 1}, {x:2}, {x:3}].reduce(function (accumulator, currentValue) {
    return accumulator + currentValue.x;
},initialValue)

console.log(sum) // 6

// 无初始值,得到不是期望的返回
var sum = [{x: 1}, {x:2}, {x:3}].reduce(function (accumulator, currentValue) {
    return accumulator + currentValue.x;
})

console.log(sum) // "[object Object]23"

10.总结

              forEachmapfor...offor...insomeeveryfilterfindfindIndexreduce
是否改变原数组××××××××××
是否有返回值×××
返回值类型×Array××BooleanBooleanArrayvalue/undefinedindex/-1累加的值
稀疏数组跳过跳过,保留空位正常遍历跳过跳过跳过跳过正常遍历正常遍历正常遍历

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值