数组方法:map
-
核心
- 创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
- 不改变原数组
- 返回值是一个新的数组
-
缺陷
- 可以使用return,但是不能使用break和continue
-
回调函数参数
- 第一个参数:
item
数组中的子元素 - 第二个元素:
index
数组元素的索引值 - 第三个元素:
arr
原数组
- 第一个参数:
let fruits= ['苹果', '梨子', '桃子', '西瓜', '哈密瓜'];
let vegetables= [{
id: 1,
name: '花椰菜'
},{
id: 2,
name: '青椒'
},{
id: 3,
name: '土豆'
},{
id: 4,
name: '西红柿'
}];
// 数组方法:map
let mapFru= fruits.map(function(item, index, arr){
item= `${item}啊!`;
console.log(arr);
return index+ ' - 爱吃'+ item;
});
console.log(mapFru);
console.log('-------------------------');
let mapVeg= vegetables.map(function(item, index, arr){
// 返回 遍历子对象
console.log(item);
// 返回 遍历索引值
console.log(index);
// 返回 所有子对象
console.log(arr);
});
数组方法 forEach
-
核心
- 对数组的每个元素执行一次提供的函数。
- 不改变原数组
- 返回值总是undefined
- map是forEach操作的具体化
-
缺陷
- 可以使用return,但是不能使用break和continue
-
回调函数参数
- 第一个参数:
item
数组中的子元素 - 第二个元素:
index
数组元素的索引值 - 第三个元素:
arr
原数组
- 第一个参数:
let fruits= ['苹果', '梨子', '桃子', '西瓜', '哈密瓜'];
let vegetables= [{
id: 1,
name: '花椰菜'
},{
id: 2,
name: '青椒'
},{
id: 3,
name: '土豆'
},{
id: 4,
name: '西红柿'
}];
// 数组方法:forEach
let forEachFru= fruits.forEach(function(item, index, arr){
item= `${item}啊!`;
// console.log(item);
// console.log(index);
// console.log(arr);
return index+ ' - 爱吃'+ item;
});
console.log(forEachFru);
console.log('-------------------------');
let forEachVeg= vegetables.forEach(function(item, index, arr){
// 返回 遍历子对象
console.log(item);
// 返回 遍历索引值
console.log(index);
// 返回 所有子对象
console.log(arr);
});
- 手动封装一个forEach
// 封装一个数组的 myForEach 方法 传参为一个函数
function myForEach(fn){
// 循环数组的每一项 谁调用的this就指向谁
for(let i = 0; i < this.length; i++){
// 循环传进来的函数的三个参数
fn(this[i],i,this)
}
}
// 定义一个数组
let arr = ['4','5','6']
// 将定义的这个数组方法放到Array的prototype下面
Array.prototype.myForEach = myForEach;
console.log(Array.prototype)
// 数组arr调用myForEach方法并传参
arr.myForEach(function(item,index,arr){
// 打印传进来的参数
console.log(item,index,arr)
})
数组方法 filter
-
核心
- 对数组的每一项都进行过滤,返回符合条件的item组成的数组
- 不改变原数组
- 返回值是经过逻辑判断后,调用数组的一个子集
- 没有任何的逻辑判断,可替代map或forEach使用,返回值为原数组
-
优点:
- 若是
arr.filter(function(){return true})
,则会跳过数组中缺少的元素,它的返回数组总是稠密的 - 返回值为判断语句,则可方便筛选提取数组内的对象元素
- 若是
-
缺陷
- 可以使用return,但是不能使用break和continue
-
回调函数参数
- 第一个参数:
item
数组中的子元素 - 第二个元素:
index
数组元素的索引值 - 第三个元素:
arr
原数组
- 第一个参数:
let fruits= ['苹果', '梨子', '桃子',, '西瓜', '哈密瓜'];
let vegetables= [{
id: 1,
name: '花椰菜'
},{
id: 2,
name: '青椒'
},{
id: 3,
name: '土豆'
},{
id: 4,
name: '西红柿'
}];
// 数组方法:filter
let filterFru= fruits.filter(function(item, index, arr){
item= `${item}啊!`;
console.log(item);
// console.log(index);
// console.log(arr);
return true;
});
console.log(filterFru);
console.log('-------------------------');
let filterVeg= vegetables.filter(function(item, index, arr){
// 返回 遍历子对象
// console.log(item);
// // 返回 遍历索引值
console.log(index);
// // 返回 所有子对象
// console.log(arr);
return item.id== 2;
});
console.log(filterVeg);
- 压缩空缺并删除
undefined
和null
元素
arr= arr.filter(function(index){
return index!== undefined && index!= null;
});
数组方法 find
-
核心
- 遍历数组,找到第一个符合条件的项,并返回该项。否则返回undefined
- 不改变原数组
- 返回值为true,则返回第一个元素
- 当找到目标值后,停止遍历,并返回目标元素
-
缺陷
- 可以使用return,但是不能使用break和continue
-
回调函数参数
- 第一个参数:
item
数组中的子元素 - 第二个元素:
index
数组元素的索引值 - 第三个元素:
arr
原数组
- 第一个参数:
let fruits= ['苹果', '梨子', '桃子',, '西瓜', '哈密瓜'];
let vegetables= [{
id: 1,
name: '花椰菜'
},{
id: 2,
name: '青椒'
},{
id: 3,
name: '土豆'
},{
id: 4,
name: '西红柿'
}];
// 数组方法:find
let findFru= fruits.find(function(item, index, arr){
item= `${item}啊!`;
// console.log(item);
// console.log(index);
// console.log(arr);
return index> 1;
});
console.log(findFru);
console.log('-------------------------');
let findVeg= vegetables.find(function(item, index, arr){
// 返回 遍历子对象
// console.log(item);
// // 返回 遍历索引值
console.log(index);
// // 返回 所有子对象
// console.log(arr);
return item.id> 1;
});
console.log(findVeg);
数组方法 findIndex
-
核心
- 遍历数组,找到第一个符合条件的项,并返回该项。否则返回-1
- 不改变原数组
-
缺陷
- 可以使用return,但是不能使用break和continue
-
回调函数参数
- 第一个参数:
item
数组中的子元素 - 第二个元素:
index
数组元素的索引值 - 第三个元素:
arr
原数组
- 第一个参数:
let fruits= ['苹果', '梨子', '桃子',, '西瓜', '哈密瓜'];
let vegetables= [{
id: 1,
name: '花椰菜'
},{
id: 2,
name: '青椒'
},{
id: 3,
name: '土豆'
},{
id: 4,
name: '西红柿'
}];
// 数组方法:findIndex
let findIndexFru= fruits.findIndex(function(item, index, arr){
// item= `${item}啊!`;
// console.log(item);
// console.log(index);
// console.log(arr);
return index> 5;
});
console.log(findIndexFru);
console.log('-------------------------');
let findIndexVeg= vegetables.findIndex(function(item, index, arr){
// 返回 遍历子对象
console.log(item.name);
// // 返回 遍历索引值
// console.log(index);
// // 返回 所有子对象
// console.log(arr);
return item.id> 2;
});
console.log(findIndexVeg);
数组方法 indexOf
-
核心
- 从前往后遍历数组,找到第一个符合条件的项,并返回该项。否则返回-1
- 不改变原数组
- 字符串也有此方法,功能类似
-
回调函数参数
- 第一个参数:
item
需要搜索的值 - 第二个元素:
index
数组中的的索引值,可以为负数,代表相对数组末尾的偏移量
- 第一个参数:
let fruits= ['苹果', '梨子', '桃子', , '西瓜', '哈密瓜'];
let vegetables= [{
id: 1,
name: '花椰菜'
},{
id: 2,
name: '青椒'
},{
id: 3,
name: '土豆'
},{
id: 4,
name: '西红柿'
}];
// 数组方法:indexOf
let indexOfFru= fruits.indexOf('桃子');
console.log(indexOfFru);
数组方法 lastIndexOf
-
核心
- 从后往前遍历数组,找到第一个符合条件的项,并返回该项。否则返回-1
- 不改变原数组
- 字符串也有此方法,功能类似
-
回调函数参数
- 第一个参数:
item
需要搜索的值 - 第二个元素:
index
数组中的的索引值,可以为负数,代表相对数组末尾的偏移量
- 第一个参数:
let fruits= ['苹果', '梨子', '桃子', , '西瓜', '哈密瓜'];
let vegetables= [{
id: 1,
name: '花椰菜'
},{
id: 2,
name: '青椒'
},{
id: 3,
name: '土豆'
},{
id: 4,
name: '西红柿'
}];
// 数组方法:lastIndexOf
let lastIndexOfFru= fruits.lastIndexOf('桃子');
console.log(lastIndexOfFru);
数组方法 every
-
核心
- 对数组中的每一项运行给定函数,如果该函数对每一项返回true,则返回true。
- 类似数学中的'针对所有',看数组的每个元素是否符合要求,都符合则返回true,否则返回false
-
缺陷
- 可以使用return,但是不能使用break和continue
-
回调函数参数
- 第一个参数:
item
数组中的子元素 - 第二个元素:
index
数组元素的索引值 - 第三个元素:
arr
原数组
- 第一个参数:
let fruits= ['苹果', '梨子', '桃子',, '西瓜', '哈密瓜'];
let vegetables= [{
id: 1,
name: '花椰菜'
},{
id: 2,
name: '青椒'
},{
id: 3,
name: '土豆'
},{
id: 4,
name: '西红柿'
}];
// 数组方法:every
let everyFru= fruits.every(function(item, index, arr){
// item= `${item}啊!`;
// console.log(item);
// console.log(index);
// console.log(arr);
return index< 6;
});
console.log(everyFru);
console.log('-------------------------');
let everyVeg= vegetables.every(function(item, index, arr){
// 返回 遍历子对象
// console.log(item);
// // 返回 遍历索引值
console.log(index);
// // 返回 所有子对象
// console.log(arr);
return item.id>= 0;
});
console.log(everyVeg);
数组方法 some
-
核心
- 是对数组中每一项运行指定函数,如果该函数对任一项返回true,则返回true。
- 类似数学中的'存在',看数组的每个元素是否符合要求,任一项返回true,否则返回true
-
缺陷
- 可以使用return,但是不能使用break和continue
-
回调函数参数
- 第一个参数:
item
数组中的子元素 - 第二个元素:
index
数组元素的索引值 - 第三个元素:
arr
原数组
- 第一个参数:
-
关于
return
return true;
遍历终止
changeNum: function(val){
// console.log(val);
// 根据子组件传过来的数据,更新list中对应的数据
this.list.some(function(item){
if(item.id == val.id){
item.num= val.num;
// 终止遍历
return true;
}
})
}
let fruits= ['苹果', '梨子', '桃子',, '西瓜', '哈密瓜'];
let vegetables= [{
id: 1,
name: '花椰菜'
},{
id: 2,
name: '青椒'
},{
id: 3,
name: '土豆'
},{
id: 4,
name: '西红柿'
}];
// 数组方法:some
let someFru= fruits.some(function(item, index, arr){
// item= `${item}啊!`;
// console.log(item);
// console.log(index);
// console.log(arr);
return index< 6;
});
console.log(someFru);
console.log('-------------------------');
let someVeg= vegetables.some(function(item, index, arr){
// 返回 遍历子对象
// console.log(item);
// // 返回 遍历索引值
console.log(index);
// // 返回 所有子对象
// console.log(arr);
return item.id>= 0;
});
console.log(someVeg);
数组方法 reduce
-
核心
- 接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值。
- 第二个参数作为第一次调用的a的值
-
缺陷
- 可以使用return,但是不能使用break和continue
let arrNum= [2, 4, 6, 8, 10];
// 累加
let sum= arrNum.reduce(function(x, y){
return x+ y;
});
console.log(sum);
// 累乘
let multiple= arrNum.reduce(function(x, y){
return x* y;
});
console.log(multiple);
// 求最大值
let bigger= arrNum.reduce(function(x, y){
return x> y? x: y;
});
console.log(bigger);
数组方法 reduceRight
-
核心
- 接收一个函数作为累加器(accumulator),数组中的每个值(从右到左)开始缩减,最终为一个值。
- 第二个参数作为第一次调用的a的值
-
缺陷
- 可以使用return,但是不能使用break和continue
let arrNum= [2, 4, 6, 8, 10];
// 累加
let sum= arrNum.reduceRight(function(x, y){
return x+ y;
});
console.log(sum);
// 累乘
let multiple= arrNum.reduceRight(function(x, y){
return x* y;
});
console.log(multiple);
// 求最大值
let bigger= arrNum.reduceRight(function(x, y){
return x> y? x: y;
});
console.log(bigger);
逻辑方法 for循环
-
核心
- 使用临时变量,并且遍历的是i.
-
缺陷
- 可以正常使用使用break和continue, 但是不能正常使用return
let fruits= ['苹果', '梨子', '桃子', , '西瓜', '哈密瓜'];
let vegetables= [{
id: 1,
name: '花椰菜'
},{
id: 2,
name: '青椒'
},{
id: 3,
name: '土豆'
},{
id: 4,
name: '西红柿'
}];
// 逻辑方法:for循环
for(let i= 0; i<fruits.length; i++){
console.log(fruits[i]);
}
console.log('-------------------------');
for(let i= 0; i<vegetables.length; i++){
console.log(vegetables[i].name);
}
逻辑方法 for...in...循环
-
核心
- 使用临时变量,并且遍历的是key.
-
缺陷
- 可以正常使用使用break和continue, 但是不能正常使用return
let fruits= ['苹果', '梨子', '桃子', , '西瓜', '哈密瓜'];
let vegetables= [{
id: 1,
name: '花椰菜'
},{
id: 2,
name: '青椒'
},{
id: 3,
name: '土豆'
},{
id: 4,
name: '西红柿'
}];
// 逻辑方法:for...in...循环
for(let key in fruits){
console.log(fruits[key]);
}
console.log('-------------------------');
for(let key in vegetables){
console.log(key);
console.log(vegetables[key].name);
}
逻辑方法 for...of...循环
-
核心
- 使用临时变量,并且遍历的是value.
-
缺陷
- 可以正常使用使用break和continue, 但是不能正常使用return
let fruits= ['苹果', '梨子', '桃子', , '西瓜', '哈密瓜'];
let vegetables= [{
id: 1,
name: '花椰菜'
},{
id: 2,
name: '青椒'
},{
id: 3,
name: '土豆'
},{
id: 4,
name: '西红柿'
}];
// 逻辑方法:for...of...循环
for(let value of fruits){
console.log(value);
}
console.log('-------------------------');
for(let value of vegetables){
console.log(value);
console.log(value.name);
}
遍历器机制
-
背景
- 截止到ES6,JavaScript 已经拥有了数组、对象、Map集合和Set集合这样四种数据结构
- 为了统一和简化遍历这四种数据结构的操作,ES6引入了遍历器机制。
-
关于
set
和map
var set = new Set();
set.add("a").add("b").add("d").add("c");
console.log(set);
var map = new Map();
map.set("a",1).set("b",2).set(999,3);
console.log(map);
for (let value of set) {
console.log(value);
}
console.log("--------------------");
for(let [key, value] of map) {
console.log(key, value);
}
- 基本概念
- ES6 规定,可遍历的对象都具有Symbol.iterator 属性,这个属性指向一个函数,就是当前对象默认的遍历器生成函数。
- 这个遍历器生成函数大致的模样可以用ES5 语法模拟出来:这个函数返回一个next() 方法,每调用next() 方法,都会返回数据结构的当前成员的信息。
- 具体来说,就是返回一个包含value和done两个属性的对象。
- 其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。
// ES5 语法模拟遍历器
function createIterator(items) {
let i = 0;
return {
next() {
let done = i >= items.length;
let value = !done ? items[i++] : undefined;
return {
done: done,
value: value
}
}
}
}
let iterator = createIterator([1, 2, 3]);
console.log(iterator.next());
//输出:{done: false, value: 1}
console.log(iterator.next());
//输出:{done: false, value: 2}
console.log(iterator.next());
//输出:{done: false, value: 3}
console.log(iterator.next());
//输出:{done: true, value:undefined }
-
默认遍历器
- 在ES6 中,已经默认为绝大多数內建的数据结构提供了遍历器,不需要像上面例子中那样自己去创建。
keys()
方法:默认遍历器,其值为集合中的所有键名。values()
方法:默认遍历器,其值为集合中的所有值。entries()
方法:默认遍历器,其值为所有成员的键值对。
-
注意:
- 扩展运算符(…)会持续调用遍历器的next() 方法,并将value属性值插入到数组中,直到结果对象的done 属性值为true。
- Set 集合的键名和键值是同一个值,所以keys() 方法和values() 方法的返回值完全一致。
const arr = ["A", "B", "C"];
console.log([...arr.keys()]);
//输出:[0, 1, 2]
console.log([...arr.values()]);
//输出:["A", "B", "C"]
console.log([...arr.entries()]);
//输出:[[0, "A"],[1, "B"],[2, "C"]]
const set = new Set(arr);
console.log([...set.keys()]);
//输出:["A", "B", "C"]
console.log([...set.values()]);
//输出:["A", "B", "C"]
console.log([...set.entries()]);
//输出:[["A", "A"],["B", "B"],["C", "C"]]
const map = new Map().set("name", "Tom").set("age", 19);
console.log([...map.keys()]);
//输出:["name", "age"]
console.log([...map.values()]);
//输出:["Tom", 19]
console.log([...map.entries()]);
//输出:[["name", "Tom"],["age", 19]]
- 不同数据结构的默认遍历器
- 每个数据结构都有一个默认的遍历器,例如数组的默认遍历器是
values()
,在没有明确指定遍历器的情况下,这些数据结构都会使用默认的遍历器。 - 我们可以通过检测对象的Symbol.iterator 属性来判断对象是否拥有遍历器。
- 每个数据结构都有一个默认的遍历器,例如数组的默认遍历器是
const arr = ["A", "B", "C"];
console.log(typeof arr[Symbol.iterator] === "function");
//输出:true
console.log(arr[Symbol.iterator]);
//输出:function values() { ... }
const set = new Set(arr);
console.log(typeof set[Symbol.iterator] === "function");
//输出:true
console.log(set[Symbol.iterator]);
//输出:function values() { ... }
const map = new Map().set("name", "Tom").set("age", 19);
console.log(typeof map[Symbol.iterator] === "function");
//输出:true
console.log(map[Symbol.iterator]);
//输出:function entries() { ... }
- 原生具备遍历器的对象
- 数组、Map集合、Set集合、字符串、arguments和 NodeList(节点列表)。
- 对象(Object)默认是不可遍历的
- 我们可以通过Object.keys()、Object.values()和Object.entries() 方法把对象变成数组,使其拥有遍历器
- 或者直接为对象添加Symbol.iterator 属性来自定义遍历器。
const obj = {
name: "Tom",
age: 19
}
console.log(typeof Object.entries(obj)[Symbol.iterator] === "function");
//输出:true
console.log([...Object.entries(obj)]);
//输出:[["name", "Tom"],["age", 19]]
const obj = {
name: "Tom",
age: 19,
[Symbol.iterator]() {
let data = [],
i = 0;
for (let k in this) {
if (this.hasOwnProperty(k)) {
data.push(Array.of(k, this[k]));
}
}
return {
next() {
let done = i >= data.length;
let value = !done ? data[i++] : undefined;
return {
done: done,
value: value
}
}
}
}
}
console.log([...obj]);
//输出:[["name", "Tom"],["age", 19]]
-
调用遍历器
- 当我们去遍历拥有遍历器的对象的时候,系统就会自动去调用对象默认遍历器的接口。没有遍历器接口的对象不能被遍历。
-
for…of 循环
- 我们知道,遍历器内部的next() 方法,每调用一次只会返回当前成员的信息
- 而for…of循环将持续调用next() 方法直到返回对象的done 属性的值为 true。
const arr = ["A", "B", "C"];
const map = new Map().set("name", "Tom").set("age", 19);
const str = "love";
for (let v of arr) {
console.log(v);
//输出:A B C
}
for (let [v, i] of map) {
console.log(v + ":" + i);
//输出:name:Tom age:19
}
for (let v of str) {
console.log(v);
//输出:l o v e
}
- 展开运算符
- 如果我们想把非数组可遍历对象的所有成员填充到一个数组中,最方便的方法是使用展开运算符(…)
- 展开运算符会触发默认的遍历器取得所有的值,然后按照取得顺序依次插入到数组中。
console.log([...new Set([1, 2, 3])]) ;
//输出:[1, 2, 3]
console.log([1, ...new Set([2, 3]), ...
"love";
])
//输出:[1, 2, 3, "l", "o", "v", "e"]
- ES6中,由于数组的遍历会调用遍历器接口,所以任何接受数组作为参数的场合,其实都调用了遍历器。例如Array.from()方法、Set()、Map()、解构赋值等等。
console.log(Array.from(new Set([1, 2, 3])));
//输出:[1, 2, 3]
let [a, b] = new Set([1, 2]);
console.log(a + "," + b);
//输出:1,2