let arr = [2, 4, 6, 56, 7, 88];
//for
for (let i = 0; i < arr.length; i++) {
console.log(i + ':' + arr[i]) //0:2 1:4 2:6 3:56 4:7 5:88
}
普通的for循环可以用数组的索引来访问或者修改原来数组对应的元素,即可以改原数组的数据
//while
let arr=[1,0,8,7],i=0;
while(i<arr.length){
console.log(i+':'+arr[i]);//0:1 1:0 2:8 3:7
i++;
}
//do while
let arr=[1,0,8,7],i=0;
do{
console.log(i+':'+arr[i]);//0:1 1:0 2:8 3:7
i++
}while(i<arr.length)
let obj = {
name: '小明',
age: 18,
hobby: 'run,song,game'
};
for(let key in obj){
console.log(key+':'+obj[key]) //name:小明 age:18 hobby:run,song,game
}
注意,对象也可以遍历的。
let arr = [2, 4, 6, 56, 7, 88];
let obj = {
name: '小明',
age: 18,
hobby: 'run,song,game'
};
for(let value of arr){
console.log(value) //2 4 6 56 7 88
}
for (let [key, value] of arr.entries()) {
console.log(key+':'+value); //0:2 1:4 2:6 3:56 4:7 5:88
}
for (let [key, value] of Object.entries(obj)) {
console.log(key+':'+value); //name:小明 age:18 hobby:run,song,game
}
注意:这个for of既可以遍历列表也可以遍历对象。
最节省内存的一种遍历方式,但是不能用break
,也不能用return
let arr = [2, 4, 6, 56, 7, 88];
let obj = {
name: '小明',
age: 18,
hobby: 'run,song,game'
};
arr.forEach((value,key)=>{
console.log(key + ':' + value) //0:2 1:4 2:6 3:56 4:7 5:88
})
Object.keys(obj).forEach((value)=>{
console.log(value) //"name", "age", "hobby"
})
既可以遍历列表也可以遍历对象。
注意:forEach会改变原来数组中的值。
let arr = [
{ id: '01001', title: '考研成绩' },
{ id: '01002', title: '中国经济复苏进度条' },
]
arr.forEach(function(item,index,arr){
item.date = "2023-1-1"
})
console.log(arr)
我们改变了原数组,并且,从上面例子可以看出,在js中,可以给一个对象直接添加一个原来没有的属性。
同forEach写法一样,循环每一个的时候就相当于在内存中新建了一个数据,比较占内存,与forEach不同的是,它可以return。返回数组。
let arr = [2, 4, 6, 56, 7, 88];
let obj = {
name: '小明',
age: 18,
hobby: 'run,song,game'
};
arr.map((value,index)=>{
console.log(index+':'+value) //0:2 1:4 2:6 3:56 4:7 5:88
})
Object.values(obj).map((value,key)=>{
console.log(key+':'+value) //0:小明 1:18 2:run,song,game
})
console.log(Object.keys(obj)) // (3) ["name", "age", "hobby"]
console.log(Object.values(obj)) // (3) ["小明", 18, "run,song,game"]
注意:map方法不会改变原来数组
let arr = [1,2,3,4,5]
let newArr = arr.map(function(item,index,arr){
return item*2
})
console.log(arr) // [1,2,3,4,5]
console.log(newArr) // [2,4,6,8,10]
但是对于数组中引用类型中的属性修改,还是会影响原来的数组中对象的属性值的。效果就和forEach一样了。
let arr = [
{ id: '01001', title: '考研成绩' },
{ id: '01002', title: '中国经济复苏进度条' },
]
let newArr = arr.map(function(item,index,arr){
item.date = "2023-1-1"
return item
})
console.log("arr",arr)
console.log("newArr",newArr)
但是可以用{…item}来做拷贝,然后我们修改拷贝后的值就行了,这样就不会影响原来的数组数据了。
let arr = [
{ id: '01001', title: '考研成绩' },
{ id: '01002', title: '中国经济复苏进度条' },
]
let newArr = arr.map(function(item,index,arr){
item = {...item} // 这里我们多了一步拷贝处理
item.date = "2023-1-1"
return item
})
console.log("arr",arr)
console.log("newArr",newArr)
扩展:
js中…的用法
1.什么是…
…是扩展运算符,是es6的新语法
2.怎么使用
作用在对象上,返回一个对象,取出对象所有可遍历属性,返回一个新的对象可以进行拷贝
基本用法
let person = { name:'张三',age:18} let someone = {...person} console.log(someone) //返回 { name:'张三',age:18 }
作用于数组对象
et array = ['a','b','c'] let obj = {...array} console.log(obj) // {0:'a',1:'b',2:'c'} 说明:给数组的每个元素生成key,从0开始返回一个新的对象
合并对象
let name = { name:'张三' } let age = { age:18 } let person = { ...name,...age } console.log(person) //{name:'张三',age:18}
属性的合并
let person = {name: "Amy", age: 15}; let someone = { ...person, name: "Mike", age: 17}; console.log(someone); //{name: "Mike", age: 17} 说明:自定义属性和扩展属性相同的时候,将会被覆盖。如果自定义属性在前,那么扩展属性覆盖自定义属性。反之则是自定义属性覆盖拓展属性。
作用:不影响原数组,这个方法会返回一个新数组。回调函数若返回true,filter就会把这一项添加到要返回的新数组中作为一个元素。
注意:传入的函数里必填return,因为会根据return的值为false或true来过滤数据。
filter的几种情况如下:
(1)直接return布尔值,为true则元素值放入数组中,为false的就被过滤掉。
例子1:
let arr = [
{ id: '01001', title: '考研成绩', isHot: true },
{ id: '01002', title: '中国经济复苏进度条', isHot: false },
]
let result = arr.filter((item) => {
return item.isHot
})
console.log(result) // [{ id: '01001', title: '考研成绩', isHot: true }]
// 看打印结果可以发现isHot为false的对象数据就被过滤掉了
例子2:
let arr = [1,2,3,4,5];
let result = arr.filter(function(item, index) {
return item>2;
});
console.log(result);
// 输出[ 3, 4, 5 ]
// item:当前元素 index:当前元素的索引值
(2)return非布尔值时,也会通过将数据隐式转化为布尔值来过滤数组。
例子:
let arr = [1,undefined,null,3,0,"",NaN]
let result = arr.filter((item) => {
return item
})
console.log(result) // [1,3]
// 将item的值转化为布尔值后,为false的元素就被过滤掉了,留下的为true的
(3)与其他方法结合使用:
这里先用一个小例子帮大家回忆一下数组的indexOf()方法的用法:用于返回某个指定的值在数组中首次出现的索引值,如果没有找到匹配的元素则返回 -1。
let arr = [1, 2, 3, 4, 5];
let index = arr.indexOf(2);
// 在数组中查找是否有2这个元素
console.log(index) //打印结果是1,表示2和数组中索引为1的元素的值匹配
①与indexOf()方法组合使用进行数组去重:
let arr = [1,1,2,4,5,6,5,5,6]
let newArr = arr.filter((item,index)=>{
return arr.indexOf(item) === index
// 因为indexOf始终返回第一个符合条件的元素的索引
// 数组中重复出现的数值就不可能满足全等判断,就会被过滤掉
})
console.log(newArr) // [1,2,4,5,6]
②还有与map方法一起使用:
let arr = [
{ id: '01001', title: '考研成绩', isHot: true },
{ id: '01002', title: '中国经济复苏进度条', isHot: false },
]
// 用map方法给数据加上日期属性
let result = arr.map((item) => {
item = {...item}
item.date = '2023-01-01'
return item
// map方法后紧接着使用filter方法过滤数据
}).filter((item) => {
return item.isHot === true
})
console.log(result)
作用:遍历数组,并构建返回一个最终的值。
语法:array.reduce(function(previous,current,index,arr),initValue);
参数说明:
①不传第二参数initValue时,我们以一个计算数组元素相加之和的例子说明:
let arr = [1,3,5,7]
let result = arr.reduce((previous,current)=>{
console.log('previous:',previous, ' current:',current)
return previous + current
})
console.log('result:',result)
打印结果为:
我们可以看到:
传入的箭头函数执行了数组长度-1次,也就是3次;
回调函数多次调用:
第一次调用时,previous表示就是数组的第一个元素的值1,current是数组第二个元素的值3;
第二次调用时,previous表示的是上次调用时return出来的值也就是1+3为4,current是数组第三个元素的值5;
第三次调用时,previous同样表示的是上次调用返回的值也就是4+5为9,current表示数组第四个元素的值7。
result的值就是最后一次计算9+7的结果值16。
②传入第二参数initValue时,我们以一个获得新数组的每个元素是原数组每个元素累计相加之和的例子说明:
let arr = [1,3,5,7]
let sum = 0
let result = arr.reduce((previous,current)=>{
console.log(previous, 'current:', current)
previous.push(sum + current)
sum += current
return previous
}, [])
console.log('result:', result)
打印结果为:
我们可以看到:
reduce的使用例子:
上面我们举了2个简单例子区分reduce方法传入1个参数和2个参数的区别,下面我以一个计算购物车选中产品数量的例子来说明项目中reduce的具体应用场景。
目前购物车一共有3个产品,其中选中了2种产品,并计算选中的总价为22393,我们可以通过reduce方法计算①②这个2个值。
// arr表示购物车里所有产品数组,其中用不到的数据就省略了
let arr = [
{
id:12334,isChecked:1, // 1表示购物车选中了这个产品
cartPrice:5999, // 表示产品单价5999
skuNum:1, // 表示购物车产品数量为1
skuName:"小米10 至尊纪念版 双模5G 骁龙865 120W快充 8GB+128GB 陶瓷黑 游戏手机",
},{
id:12375,
isChecked:0, // 0表示购物车没有选中这个产品
cartPrice:2323, // 表示产品单价为2323
skuNum:1, // 表示购物车产品数量为1
skuName:"华为P40 5G全网通智能手机 支持鸿蒙HarmonyOS 零度白 8G+128G",
},{
id:12376,
isChecked:1, // 1表示购物车选中了这个产品
cartPrice:8197, // 表示产品单价为8197
skuNum:1, // 表示购物车产品数量为1
skuName:"Apple iPhone 12 (A2404) 64GB 黑色 支持移动联通电信5G 双卡双待手机",
}
]
因为每个产品对象的isChecked属性1就表示选中了,0表示没有选中,因此我们可以通过累计相加这个值来计算购物车选择的产品数:
// 计算购物车选中产品数
let num = arr.reduce((previous,current)=>{
return previous + current.isChecked
// previous初始值是传入的第二个参数0,current表示数组的当前遍历到的对象
},0)
// 通过累计相加所有产品的isChecked的属性值,获得选中的产品数量num为2
//计算选中产品总价格,我们也是通过reduce方法累计计算:
// 计算购物车选中产品总价格
let price = arr.reduce((previous,current)=>{
return previous + current.isChecked * current.cartPrice * current.skuNum
// 选中的产品的数量和价格的乘积累计相加
},0)
// 最终的price的值就是选中产品总价
通过上面的例子我们可以看到这种要累计计算处理数据的情况,使用reduce方法是比较方便的操作。
因为some()方法和every()方法比较简单,因为比较相似所以这里也是一起讲解。
(1)some()方法用于检测数组中的元素是否满足return的判断条件,如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测;如果没有满足条件的元素,则返回false。
// some方法只要有一个元素符合return的条件就返回true,后面元素就不会再执行判断
let arr = [2,3,4,6]
let result = arr.some((item)=>{
return item % 2 === 1 // 判断数组的每个元素是否除以2能余1
})
console.log(result) // 因为第二个元素3符合,所以结果为true
(2)every()方法用于检测数组中的元素是否都满足return的判断条件,只要有一个不符合就会返回false,都符合才返回true。
// every方法要求所有元素符合return的判断条件才返回true,不然就返回false
let arr = [2,3,4,6]
let result = arr.every((item)=>{
return item % 2 === 0 // 判断数组的每个元素是否都能被2整除
})
console.log(result) // 因为第二个元素3不符合条件,所以结果为false
for:简单、可以通过索引访问或者修改原数组
while、do while:循环条件确定,和java一样
for in:可以遍历对象出对象的属性和属性值。
for of:既可以遍历列表也可以遍历对象。可以拿到列表的索引和值,也可以拿到对象的属性和属性值
forEach:省内存,但是不能使用for寻找中的break。可以拿到数组的索引和元素。可以获取对象中的属性值。注意:forEach会改变原来数组中的值。forEach方法没有返回值,一般用于直接修改原数组;
map:不会改变原来数组。但是对于引用数据类型还是会影响原来数组中的对象的属性的。但是可以用过{… 对象}的语法来解决这个问题。map会返回一个数组对象,这个数组对象就是被改变后的对象。
filter:filter()方法用于过滤列表,返回的结果就是过滤后的新数组。这个还是很好用的。
reduce:一般我们用来做累加
some:判断列表中是否有某个元素符合某个规则
every:判断列表中是否全部元素都符合某个规则
注意:js中可以给一个对象直接添加原来没有的属性。