一、for-in 和 for-of 的区别
for-in循环主要用于遍历对象,for()中的格式:for(keys in zhangsan){}
keys表示obj对象的每一个键值对的键!!所有循环中,需要使用obj[keys]来取到每一个值!!!for-in 循环,遍历时不仅能读取对象自身上面的成员属性,也能延续原型链遍历出对象的原型属性所以,可以使用hasOwnProperty判断一个属性是不是对象自身上的属性obj.hasOwnProperty(keys)==true 表示这个属性是对象的成员属性,而不是原先属性。
//声明一个Peson类
function Person(){
this.name = "张三";
this.age = 14;
this.func1 = function(){
}
}
//实例化这个类
var zhangsan = new Person();
//使用for-in遍历这个对象
for(keys in zhangsan){
console.log(zhangsan[keys])
}
for…of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串
1. 数组
var arr = ['a', 'b', 'c', 'd'];
for (let a in arr) {
console.log(a); // 0 1 2 3
}
for (let a of arr) {
console.log(a); // a b c d
}
12345678910
上面代码表明,for…in循环读取键名,for…of循环读取键值。如果要通过for…of循环,获取数组的索引,可以借助数组实例的entries方法和keys方法
2.Set 和 Map 结构
var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
for (var e of engines) {
console.log(e);
}
// Gecko Trident Webkit
var es6 = new Map();
es6.set("edition", 6);
es6.set("committee", "TC39");
es6.set("standard", "ECMA-262");
for (var [name, value] of es6) {
console.log(name + ": " + value);
}
// edition: 6
// committee: TC39
// standard: ECMA-26212345678910111213141516
上面代码演示了如何遍历 Set 结构和 Map 结构。值得注意的地方有两个,首先,遍历的顺序是按照各个成员被添加进数据结构的顺序。其次,Set 结构遍历时,返回的是一个值,而 Map 结构遍历时,返回的是一个数组,该数组的两个成员分别为当前 Map 成员的键名和键值。
3.类似数组的对象
类似数组的对象包括好几类。下面是for…of循环用于字符串、DOM NodeList 对象、arguments对象的例子。
// 字符串
var str = "hello";
for (let s of str) {
console.log(s); // h e l l o
}
// DOM NodeList对象
let paras = document.querySelectorAll("p");
for (let p of paras) {
p.classList.add("test");
}
// arguments对象
function printArgs() {
for (let x of arguments) {
console.log(x);
}
}
printArgs('a', 'b');// 'a' 'b'1234567891011121314151617
与其他遍历语法的比较
for…in循环有几个缺点
①数组的键名是数字,但是for…in循环是以字符串作为键名“0”、“1”、“2”等等。
②for…in循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。
③某些情况下,for…in循环会以任意顺序遍历键名。
for…in循环主要是为遍历对象而设计的,不适用于遍历数组。for…of循环
有着同for…in一样的简洁语法,但是没有for…in那些缺点。
不同于forEach方法,它可以与break、continue和return配合使用。
提供了遍历所有数据结构的统一操作接口
二、forEach()、map()、every()、some()和filter()的用法
1.forEach(),用于遍历数组,无返回值
这里先给出一个数组(以下例子通用):
var arr = [1,-2,3,4,-5];
然后我要做事情的就是,将数组中的每一项翻倍。
arr.forEach(function(item,index,array){
array[index] = item * 2;
});
console.log(arr); // [2,-4,6,8,-10]
可以看到,forEach()可以传入一个匿名函数作为参数,而该匿名函数有含有三个参数,其依次代表数组遍历时的当前元素item,数组遍历时的当前元素的索引index,以及正在遍历的数组array。有了这三个参数,可以方便我们做很多事情,比如说示例当中将每一项数组元素翻倍,这时需要用到第一个参数item。但是,仅仅只是将item乘以2可不行,我们还得将其赋值给原来的数组,这时我们就得用到后面两个参数index和array。
根据上述可知,array[index]是全等于item的。
arr.forEach(function(item,index,array){
console.log(array[index] === item); // true
});
2.map(),用于遍历数组,返回处理之后的新数组
var newArr = arr.map(function(item,index,array){
return item * 2;
});
console.log(newArr); // [2,-4,6,8,-10]
可以看到,该方法与forEach()的功能类似,只不过map()具有返回值,会返回一个新的数组,这样处理数组后也不会影响到原有数组。
3.every(),用于判断数组中的每一项元素是否都满足条件,返回一个布尔值
var isEvery = arr.every(function(item,index,array){
return item > 0;
});
console.log(isEvery); // false
可以看到,示例中是要判断数组arr中的元素是否都为正数,很显然不是,所以该方法最终返回false。
4.some(),用于判断数组中的是否存在满足条件的元素,返回一个布尔值
var isSome = arr.some(function(item,index,array){
return item < 0;
});
console.log(isSome); // true
可以看到,该方法与every()类似,示例中是要判断数组arr中是否存在负数元素,很显然存在,所以该方法最终返回true。
5.filter(),用于筛选数组中满足条件的元素,返回一个筛选后的新数组
var minus = arr.filter(function(item,index,array){
return item < 0;
});
console.log(minus); // [-2, -5]
可以看到,示例中是要筛选出数组arr中的所有负数,所以该方法最终返回一个筛选后的新数组[-2, -5]。
补充: 以上五大方法除了传递一个匿名函数作为参数之外,还可以传第二个参数,该参数用于指定匿名函数内的this指向,例如:
// 只传一个匿名函数
arr.forEach(function(item,index,array){
console.log(this); // window
});
// 传两个参数
arr.forEach(function(item,index,array){
console.log(this); // [1, -2, 3, 4, -5]
},arr);
三、判断和查找
-
includes()
和indexOf
是用元素对参数精确匹配===
进行查找 -
find()
和findIndex()
是传入比较行为(函数),按指定方式查找console.log([1, 2, 3, 4, 5].includes(3));
const a = { v: 3 }; const array = [ { v: 1 }, { v: 2 }, { v: 3 }, { v: 4 }, ]; console.log(array.includes(a));
const arr = [ { v: 1} { v: 2} ];
const a = { v: 2 }
// console.log(!!);
count f = array.find(it => it.v === a.v) // 此时 f !== a
console.log(array.find(it => it.v === a.v)); console.log(array.findIndex(it => it.v === a.v) >= 0);
console.log(!![0, 1, 2, 3].find(it => it === 0));
四、获取数组对象中某个属性的最大值或最小值
数组对象如下,求id的最大值和最小值
list: [
{ id: 1, name: 'jack' },
{ id: 2, name: 'may' },
{ id: 3, name: 'shawn' },
{ id: 4, name: 'tony' },
]
1、Math方法
// 最大值 4
Math.max.apply(Math,this.list.map(item => { return item.id }))
// 最小值 1
Math.min.apply(Math,this.list.map(item => { return item.id }))
2、sort排序
需要注意的是,sort()对数组排序,不开辟新的内存,对原有数组元素进行调换, 所以这种操作会使得原来的数组元素的位置发生变化
// 最大值 4
this.list.sort((a, b) => { return b-a })[0].id
// 最小值 1this.list.sort((a, b) => { return a-b })[0].id
五、向一个对象数组里面添加新的属性
向一个对象数组里面添加新的属性
var arry= [{a:11,b:22,c:33,d:44},{a:11,b:0,c:0,d:44},{a:11,b:22,c:99,d:99}];
var arry2=[];
arry.map(((item, index)=> {
arry2.push(Object.assign({},item,{mess1:item.c,mess2:item.d}))
}))
console.log(arry2);
将一个对象数组数据拿出来变成另一个对象
var arry= [{a:11,b:22,c:33,d:44},{a:11,b:0,c:0,d:44},{a:11,b:22,c:99,d:99}];
var arry2=[];
arry.map(((item, index)=> {
arry2.push(Object.assign({},{mess1:item.c,mess2:item.d}))
))
console.log(arry2);
六、树形数据处理(经典实际运用)
一.数组对象不匹配
后端返回数据格式:
data: [
{
id: '003268955',
name: 'tom',
age: 18
},
{
id: '0335689754',
name: 'mark',
age: 23
}
];
- 假设:
-
这里的id返回的类型是string,而你需要的是number类型
data = data.map(res => { return { ...res, id: Number(res.id) } }) //输出=> [ { id: 3268955, name: 'tom', age: 18 }, { id: 335689754, name: 'mark', age: 23 } ];
2.后端返回的是name字段名,而你需要的是username(这里我们直接复制出一个新的key就行,旧的key值可以保留也可删除)
//不删除旧key
data = data.map(res => {
return {
...res,
username: res.name
}
})
//输出=>
[
{ id: '003268955', name: 'tom', age: 18, username: 'tom' },
{ id: '0335689754', name: 'mark', age: 23, username: 'mark' }
];
//删除旧key
data = data.map(res => {
let username = res.name
delete res.name
return {
...res,
username: username
}
})
//输出=>
[
{ id: '003268955', age: 18, username: 'tom' },
{ id: '0335689754', age: 23, username: 'mark' }
];
3.checkbox情况,你还需要一个变量checked来处理有没有被选择的情况(初始值置为false)
data = data.map(res => {
let username = res.name
delete res.name
return {
...res,
checked: false
}
})
//输出=>
[
{ id: '003268955', age: 18, checked: false },
{ id: '0335689754', age: 23, checked: false }
];
二、树状数据结构
后端返回数据:
[
{
title: '一号楼',
key: '100',
children: [
{
title: '一单元',
key: '1001',
children: [
{ title: '3405', key: '10010' },
{ title: '3302', key: '10011' }
]
}
]
}
];
- 假设
1.使用的树插件的key以及value字段名称是id和name;(递归方式进行替换并删除旧key)
function format(data){
data.forEach(res=>{
res.id = res.key;
res.name = res.title;
delete res.key;
delete res.title;
if(res.children){
format(res.children)
}
})
}
format(data)
//输出==>
[ { children: [ { children: [ { id: '10010', name: '3405' }, { id: '10011', name: '3302' } ],
id: '1001',
name: '一单元'
}
],
id: '100',
name: '一号楼'
}
];
2.希望在最后一个节点显示前面父集的集合:一号楼一单元10010
function format(data,text){
data.forEach(res=>{
if(!res.children){
res.title = text + res.title
}
if(res.children){
text += res.title;
format(res.children,text)
}
})
}
format(data,'');//初始text置为空
//输出==>
[ { title: '一号楼', key: '100', children: [ { title: '一单元', key: '1001', children: [ { title: '一号楼一单元3405', key: '10010' }, { title: '一号楼一单元3302', key: '10011' } ]
}
]
}
];
3.将节点进行排序
const compare = p => (m, n) => m[p] - n[p];
function format(data, key) {//key:需要排序的字段
data.sort(compare(key));
data.forEach(res => {
if (!res.children) {
return;
} else {
format(res.children, key);
}
});
}
format(data, 'title');
//输出=>
[ { title: '一号楼', key: '100', children: [ { title: '一单元', key: '1001', children: [ { title: '3302', key: '10011' }, { title: '3405', key: '10010' } ]
}
]
}
];
七、无敌的reduce()
reduce()方法可以搞定的东西,for循环,或者forEach方法有时候也可以搞定,那为啥要用reduce()?这个问题,之前我也想过,要说原因还真找不到,唯一能找到的是:通往成功的道路有很多,但是总有一条路是最捷径的,亦或许reduce()逼格更高...
1、语法
arr.reduce(callback,[initialValue])
reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组。
callback (执行数组中每个值的函数,包含四个参数)
1、previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
2、currentValue (数组中当前被处理的元素)
3、index (当前元素在数组中的索引)
4、array (调用 reduce 的数组)
initialValue (作为第一次调用 callback 的第一个参数。)
2、实例解析 initialValue 参数
先看第一个例子:
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 2 1
3 3 2
6 4 3
[1, 2, 3, 4] 10
这里可以看出,上面的例子index是从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);
打印结果:
0 1 0
1 2 1
3 3 2
6 4 3
[1, 2, 3, 4] 10
这个例子index是从0开始的,第一次的prev的值是我们设置的初始值0,数组长度是4,reduce函数循环4次。
结论:如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。
注意:如果这个数组为空,运用reduce是什么情况?
var arr = [];
var sum = arr.reduce(function(prev, cur, index, arr) {
console.log(prev, cur, index);
return prev + cur;
})
//报错,"TypeError: Reduce of empty array with no initial value"
但是要是我们设置了初始值就不会报错,如下:
var arr = [];
var sum = arr.reduce(function(prev, cur, index, arr) {
console.log(prev, cur, index);
return prev + cur;
},0)
console.log(arr, sum); // [] 0
所以一般来说我们提供初始值通常更安全
3、reduce的简单用法
当然最简单的就是我们常用的数组求和,求乘积了。
var arr = [1, 2, 3, 4];
var sum = arr.reduce((x,y)=>x+y)
var mul = arr.reduce((x,y)=>x*y)
console.log( sum ); //求和,10
console.log( mul ); //求乘积,24
4、reduce的高级用法
(1)计算数组中每个元素出现的次数
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}
(2)数组去重
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]
(3)将二维数组转化为一维
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]
(3)将多维数组转化为一维
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]
(4)、对象里的属性求和
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