遍历迭代Api,它们的作用,应用场景,参数,以及返回值分别是什么。
forEach、map、some、every、filter(今天的主角)
我们统一设定一个初始数组:
let array = [1,5,9,2,4,6];
1. forEach(callback)
对数组的每个元素执行一次提供的参数。callback是一个函数,在遍历数组的每个元素时,都会去调用该函数执行
callback函数结构function(currentValue, index, array) {
- currentValue表示的是当前遍历到的数组元素值
- index表示的是当前遍历到的数组元素下标
- array表示的是当前调用forEach()方法的数组对象
}
使用方法:
let newArray = [];
array.forEach((item, index, arr) => {
console.log('currentValue:', item)
console.log('index:', index)
console.log('arr:', arr)
newArray.push(item * 2)
})
console.log(newArray)
输出的结果如下:
一般笔者遍历数组的时候喜欢用forEach替换for循环
2. map(callback)
创建一个新数组,其结果是该数组中每个元素都调用一个提供的函数后返回的结果。
即map()方法调用后返回一个新数组,新数组中的元素是callback函数的返回值。
使用方法:
let newArray = array.map((item, index) => {
console.log('currentValue:', item)
console.log('index:', index)
return item * 2
})
console.log(newArray)
输出结果如下:
3. some(callback)
测试数组中的某些元素是否通过由提供的函数实现的测试
测试,返回boolean值,每个元素都会调用执行callback函数,当callback函数返回为false时,继续遍历下一个元素,直到遍历结束,最终返回false。如果在遍历到某个元素时,callback返回true则结束遍历,some()返回true的结果。
使用方法:
let mark = array.some((item, index) => {
console.log('currentValue:', item)
console.log('index:', index)
return (item < 0)
})
console.log(mark)
PS:判断遍历到的内容是否小于0,如果为false则判断下一个,如果为true则直接返回true值,不在进行接下来的遍历了。
上面代码输出结果如下:
因为没有小于0的,所以最终的返回值是false。
我们换个条件再来测试一下:
let mark = array.some((item, index) => {
console.log('currentValue:', item)
console.log('index:', index)
return (item < 2)
})
console.log(mark)
我们将判断改成了是否小于2。
输出结果如下:
可以发现只遍历了第一个值发现就满足条件了,所以直接跳出遍历,返回true的结果。
4. every(callback)
测试数组中的每一个元素是否通过由提供的函数实现的测试必须全部符合条件才会返回true,否则返回false。
测试代码如下:
let mark = array.every((item, index) => {
console.log('currentValue:', item)
console.log('index:', index)
return (item < 2)
})
console.log(mark)
输出结果如下:
every其实是与some刚刚好相反,some是遇到条件满足的退出循环返回true,而every是遇到条件不满足的退出循环返回false。some是有一个满足就返回true,而every是全部满足才会返回true。
5. filter(callback)
过滤,筛选出callback函数返回值为true的对应元素,放到新的数组中。
测试代码如下:
let newArray = array.filter((item, index) => {
console.log('currentValue:', item)
console.log('index:', index)
return (item < 6)
})
console.log(newArray)
输出结果如下:
7、伪数组的介绍:
1、伪数组拥有数组的属性,
-具有 length 属性 但length属性不是动态的,不会随着成员的变化而变化
-按索引方式储存数据
-不具有数组的push(), forEach()等方法
2、伪数组本质是一个 Object,而真实的数组是一个 Array。
伪数组的原型 Object.__prototype__ 通过改变原型指向可以将伪数组转为真数组
常见伪数组
一个是arguments还有一个是DOM的children属性,获取回来的子节点集合。他们与数组一样,具有索引(下标)和length属性。可以通过for循环写循环语句去循环遍历。我们可以简单看一下伪数组的样子:
arguments伪数组的样子:
children伪数组的样子:
伪数组转为真数组
遍历添加入一个空数组
var arr = [];
for(var i = 0; i < arrLike.length; i++){
arr.push(arrLike[i]);
}
利用数组的slice()方法
[].slice.call(arrLike);
//slice() 方法以新的数组对象,返回数组中被选中的元素。
或者
Array.prototype.slice.apply(arrLike);
使用slice()返回一个新的数组,用call()或apply()把他的作用环境指向伪数组。slice 返回的数组中,不会保留索引值以外的其他额外属性。
模拟 slice() 内部实现
Array.prtotype.slice = function(start, end){
var result = new Array();
var start = start | 0;
var end = end | this.length;
for(var i = start; i < end; i++){
result.push(this[i]);
}
return result;
}
改变原型指向
arrLike.__proto__ = Array.prototype;
通过改变原型指向,arrLike就继承了Array.prototype中的方法,可以使用push(),unshift()等方法了,length值也会随之动态改变。
这种直接修改原型链的方法,还会保留下伪数组中的所有属性,包括不是索引值的属性。
Array.from()
Array.from() 方法从一个类似数组或可迭代对象中创建一个新的数组实例。
var arr = Array.from(arrLike);
只保留索引值内的属性。
8、如何判断数组
1.使用instanceof
arr instanceof Array
大部分情况都可以用instanceof判断是否是数组,但是在判断一个变量是对象或非对象时,会存在坑,
因为 instanceof 在判断数组时,即会把数组当做Array类型,又会把数组当做Object类型,所以要严格验证一个数组,最好是用constructor,能严格区分数组和对象。
2.使用constructor
console.log([].constructor == Array); //true
console.log({}.constructor == Object); //true
console.log("string".constructor == String); //true
console.log((123).constructor == Number); //true
console.log(true.constructor == Boolean); //true
3.使用Object.prototype.toString.call(arr) === ‘[object Array]’, 重点记住object Array
4.使用Array.isArray 判断
Array.isArray([1, 2, 3]);
// true
Array.isArray({foo: 123});
// false
Array.isArray("foobar");
// false
Array.isArray(undefined);
// false
数组遍历
结果:
方法1、双重for循环
这是一个最笨的方法,双重循环。
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 数组去重:
// 方法1: 双重for 循环
function newArrFn (arr) {
// 创建一个新的空数组
let newArr = []
for(let i = 0;i<arr.length;i++){
// 设置一个开关,如果是true,就存进去,不是就不存
let flag = true
for(let j = 0;j<newArr.length;j++){
// 原数组和新数组作比较,如果一致,开关变为 false
arr[i] === newArr[j] ? flag = false : flag
};
//flag 为false就存进去
flag ? newArr.push(arr[i]) : newArr
};
return newArr
}
console.log(newArrFn(arr));
方法2、for循环 +findIndex (indexOf)
主要利用findIndex 的特性,查找元素找不到就返回-1, 接下来就需要判断,如果是-1,说明没找到,就往新数组里面添加元素。
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 数组去重:
// 方法2: for + indexof
function newArrFn (arr) {
let newArr = []
for(let i = 0;i<arr.length;i++){
console.log(newArr.indexOf(arr[i]),'------------------');
//为-1说明没找到,没有重复、就往新数组里面添加元素。
newArr.indexOf(arr[i]) === -1 ? newArr.push(arr[i]) : newArr
};
return newArr
}
console.log(newArrFn(arr));
方法3、sort 排序
首先利用 sort 方法进行排序。进行循环,如果原数组的第 i 项和新数组的 i - 1 项不一致,就push进去。
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 数组去重:
// 方法3: for + sort
function newArrFn (arr) {
arr = arr.sort()
let newArr = []
console.log(arr,'arr=========');
for(let i = 0;i<arr.length;i++){
console.log(arr[i],arr[i-1]);
arr[i] === arr[i-1] ? newArr : newArr.push(arr[i])
};
return newArr
}
console.log(newArrFn(arr));
方法4、Set
ES6中新增了数据类型Set,Set的一个最大的特点就是数据不重复。Set函数可以接受一个数组(或类数组对象)作为参数来初始化,利用该特性也能做到给数组去重。
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 数组去重:
// 方法4: set
function newArrFn (arr) {
// .new Set方法,返回是一个类数组,需要结合 ...运算符,转成真实数组
return ([...new Set(arr)])
}
console.log(newArrFn(arr));
方法5、set + Array.from
利用 set数据不重复的特点,结合 Array.from
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 数组去重:
// 方法5: set + Array.from
function newArrFn (arr) {
// .new Set方法,返回是一个类数组,需要结合 Array.from ,转成真实数组
return (Array.from(new Set(arr)) )
}
console.log(newArrFn(arr));
方法6、filter + indexOf
indexOf,可以检测某一个元素在数组中出现的位置,找到返回该元素的下标,没找到返回 -1
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 数组去重:
// 方法6 :filter + findIndex
function newArrFn (arr) {
// 利用indexOf检测元素在数组中第一次出现的位置是否和元素现在的位置相等,
// 如果相等,说明数组中没有重复的
return Array.prototype.filter.call(arr, function (item, index) {
return arr.indexOf(item) === index
})
}
console.log(newArrFn(arr));
方法7、includes
利用 includes 检查新数组是否包含原数组的每一项。 如果不包含,就push进去
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 数组去重:
// 方法7 :for + includes
function newArrFn (arr) {
// 利用includes 检查新数组是否包含原数组的每一项
// 如果不包含,就push进去
let newArr = []
for(let i = 0;i<arr.length;i++){
newArr.includes(arr[i]) ? newArr: newArr.push(arr[i])
};
return newArr
}
console.log(newArrFn(arr));
方法 8、 for + object
利用对象属性名不能重复这一特点。如果对象中不存在,就可以给 push 进去
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 数组去重:
// 方法8 :for + splice
// 利用 splice 进行切割。
function newArrFn (arr) {
for(let i = 0; i<arr.length; i++){
for(let j = i + 1; j<arr.length; j++){
if (arr[i] === arr[j]) {
arr.splice(j,1);
j--
}
};
}
return arr
}
console.log(newArrFn(arr));
方法9、for + splice
利用 splice 进行切割
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 数组去重:
// 方法8 :for + splice
// 利用 splice 进行切割。
function newArrFn (arr) {
for(let i = 0; i<arr.length; i++){
for(let j = i + 1; j<arr.length; j++){
if (arr[i] === arr[j]) {
arr.splice(j,1);
j--
}
};
}
return arr
}
console.log(newArrFn(arr));
方法10、filter + indexOf
利用 filter 过滤 配合 indexOf 查找元素
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 数组去重:
// 方法10 :filter + indexOf
// filter 过滤 配合 indexOf 查找元素
function newArrFn (arr) {
return arr.filter((item, index) => {
return arr.indexOf(item) === index
})
}
console.log(newArrFn(arr));
方法11、Map
利用数据结构存值的特点
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 数组去重:
// 方法11 :Map
function newArrFn (arr) {
let newArr = []
let map = new Map()
for(let i = 0;i<arr.length;i++){
// 如果 map里面不包含,就设置进去
if (!map.has(arr[i])) {
map.set(arr[i], true)
newArr.push(arr[i])
}
};
return newArr
}
console.log(newArrFn(arr));
方法12:reduce
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 数组去重:
// 方法12 :reduce
function newArrFn (arr) {
let newArr = []
return arr.reduce((prev, next,index, arr) => {
// 如果包含,就返回原数据,不包含,就把新数据追加进去
return newArr.includes(next) ? newArr : newArr.push(next)
}, 0)
}
console.log(newArrFn(arr));