知其然,知其所以然
真的很重要,带着一知半解去,那么构建起来的知识就如同空中楼阁一般,禁不起推敲和实践。记得曾今学过JavaScript的很多数组的方法,但到头来只是写出一个一个的 for 循环,每种类型间的区别都不清楚,那么怎么能明白灵活使用呢?这里我们重新去学习,了解每一个的特点,以及他所对应的使用场景。做到心中有数。才能对拿到的数据做出适合我们的调整和组合。
哈哈哈,其实也没啥,就学习和运用一下JavaScript的关于数组的api,以及便于自己日常忘了的时候来查阅,并且方便自己添加使用过程中遇到的问题和技巧。
for(var i = 0; i < len.length; i++){
console.log("你好帅呀!");
}
//这是展示一种优化后的
for(var i = 0,len = XXX.length; i < len; i++){
console.log("你好帅呀!");
}
为什么这么写就能优化循环呢?
其实我们每次循环的过程会有几个步骤(以上面的代码为例):
所以我们可以看出,当我们把获取长度的,变为局部变量,就能减少执行,达到优化的目的了。
虽然可怜的for循环已近渐渐离开我们的身边了,泪目,想当年,实习前,它还陪伴我度过无数个日夜。
let person = {
name: {
firstName: 'lala',
secondName: 'wawa'
},
age: 16,
sex: 'boy'
}
person.hobby = 'song'
for (item in person) {
console.log(person[item])
}
console.log('*************')
for (item in person) {
console.log(item)
}
//输出结果
//{firstName: "lala", secondName: "wawa"}[[Prototype]]
//16
//boy
//song
//*************
//name
//age
//sex
//hobby
//输出数组
let arr = [1,2,3];
for(let item in arr){
console.log( '------' , item, arr[item])
console.log('****' ,item+item);
}
//输出结果
//------ 0 1
//**** 00
//------ 1 2
//**** 11
//------ 2 3
//**** 22
那么我们一般什么时候用到这个循环方法呢?一般在我们需要遍历对象,获取属性的时候用到多点,当然,遍历数组也是可以的。但是不建议,因为我们可以看出上面,当操作数组的时候,返回的item是字符串格式,不是数组下标的形式所以,返回了00,11,22,而不是0 ,2,4。这个是个需要注意的地方。
特点
他的效率比较低的具体分析,后面再来详细研究一下为啥吧!
let iterable = new Map([["a", 1], ["b", 2], ["c", 3]]);
for (let entry of iterable) {
console.log(entry);
}
// ["a", 1]
// ["b", 2]
// ["c", 3]
for (let [key, value] of iterable) {
console.log(value);
}
// 1
// 2
// 3
我们就看一个map的例子就好了,因为它的使用和 for in大体是相同的,来自ES6的语法,他解决了很多for in会带来的困惑,使得更加的好用,但我们要留意兼容性。下面我们来看看他们的区别,以及改进了什么。
for of和for in的区别
//回调函数可以有三个值(当前值,当前值索引,数组对象本身)
let arr = [1,2,3,4,5,6];
arr.forEach((item,index ,arr)=>{
console.log("------>item" , item);
console.log("------>index" , index);
arr[index] = item +1;
console.log("------>addarr" , arr);
})
//输出结果
------>item 1
------>index 0
------>addarr [ 2, 2, 3 ]
------>item 2
------>index 1
------>addarr [ 2, 3, 3 ]
------>item 3
------>index 2
------>addarr [ 2, 3, 4 ]
根据它的特点,那么我们常用的情况肯定是对于数组的操作,并且这个过程不需要中断,且对原数组不会造成影响,如果有其他的要求,那么建议使用另外一种方法来操作比较适合了,另外他不支持 continue,非要的话,用 return false 或 return true 代替。break,可以用 try catch/every/some 代替。
forEach中return无效
为什么呢?
因为:forEach()无法在所有元素都传递给调用的函数之前终止遍历,也就是不可中断
forEach 和 for 关于return 的区别
直接在 for 循环中使用 return会报错,在 forEach 中使用 return 不会报错,但是并不会生效,如果我们真的需要 return 返回某个值,只能把 return 操作放在函数中,而在 forEach() 中的 return 只会结束此次循环,执行下一次循环,但 for 中的 return 会直接跳出循环,不再执行下面的循环
//同上面的forEach,回调函数有三个值(当前值,当前值索引,数组对象本身)
let arr = [1,2,3,4,5,6];
const find = arr.find(item=>item>3)
console.log(find);
//输出结果
4
//还可以下面这种用法,用一个方法的形式。麻烦的操作,非要实现的话,可以用很多其他的方法,没必要这样~~~~
var inventory = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5}
];
function findCherries(fruit) {
return fruit.name === 'cherries';
}
console.log(inventory.find(findCherries));
//输出结果
//{ name: 'cherries', quantity: 5 }
这玩意是ES6的,要注意兼容性。
let arr = [1,2,3,4,5,6];
const findIndex = arr.findIndex(item=>item>3)
console.log(findIndex);
//输出结果
//3
俺就不明白为啥还有这个方法,这个作用不是可以在find里面就能实现吗?迷惑ing
//回调函数有三个值(当前值,当前值索引,数组对象本身)
const iftrue = (item) => item < 5;
const arr = [1, 3,4];
console.log(arr.every(iftrue));
// 输出结果
//true
一旦找到一个不符合函数条件的,就会终止迭代,返回false
//回调函数有三个值(当前值,当前值索引,数组对象本身)
const iftrue = (item,index,arr) => item < 5;
const arr = [10, 8,4];
console.log(arr.some(iftrue));
// 输出结果
//true
只要有一个符合就会返回 true, 反之返回 false。他和 every有点相似的,区别在于,前者是全部通过才为 true ,后者是只要有一项符合就为true
//回调函数可以传入有四个值reduce(accumulator, currentValue, index, array )前面两项是必须传入的。
const arr = [1, 3, 4, 5];
console.log(arr.reduce( (accum ,item) => accum + item));
//输出结果
//8
该方法在运行的过程中,我们知道有四个参数,前面两个是必须传的。
在这里你是否发现,我们本身数租是长度为 4 的,但是方法只是执行了三遍就结束了。并且在方法第一次循环的开始,并不是从索引为 0 开始,是从 1 开始。
下面我们就说看看该方法除了回调函数外的另一个参数 initialValue,这个参数是作为 accun的初始值,没提供的话,会默认为数组的第一项。那么我们上面的例子,要是我们给 accum 设置初始值为 0,那么这个执行的过程就会多了一次,变为四次,索引从0开始。并且使用索引值还可以避免数组为空的时候导致的报错现象。
下面看看,一些MDN提供的一些好的用法,来带个大家在使用上的一些启示吧!更多的大家可以去官网看看!
数组去重
let myArray = ['a', 'b', 'a', 'b', 'c', 'e', 'e', 'c', 'd', 'd', 'd', 'd']
let myOrderedArray = myArray.reduce(function (accumulator, currentValue) {
if (accumulator.indexOf(currentValue) === -1) {
accumulator.push(currentValue)
}
return accumulator
}, [])
console.log(myOrderedArray)
将二维数组转化为一维
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(
function(a, b) {
return a.concat(b);
},
[]
);
// flattened is [0, 1, 2, 3, 4, 5]
//回调函数有三个值(当前值,当前值索引,数组对象本身)
let numbers = [1, 4, 9];
let roots = numbers.map(Math.sqrt);
let quent = numbers.map(item => [item * 2])
console.log("---------->number" , number)
console.log("---------->roots" , roots)
console.log("---------->quent" , quent)
//输出结果为:
//---------->number[1, 4, 9]
//---------->roots[1, 2, 3]
//---------->quent[[1], [4], [9]]
根据他返回一个新的数组的特点,当我们需要保留原数组不变,并且生成新的数组时,我们可以用该方法。
//默认传入的参数为1,可以传入不同的数值来指定扁平的深度
const arr = [0, 1, 2, [3, 4, [5] ] ];
console.log('--------->' , arr.flat());
console.log('********>' , arr.flat(2));
//输出结果:
// --------->[0, 1, 2, 3, 4, [5] ]
//'********>[0,1,2,3,4,5 ]
除了扁平化数组外,还可以去除数组中的空项的。另外,要扁平化数组的话,还可以用展开运算符(…)
//回调函数有三个值(当前值,当前值索引,数组对象本身)
let arr1 = [1, 2, 3, 4];
console.log('----->1' , arr1.map(x => [x * 2]));
console.log('----->2' , arr1.flatMap(x => [x * 2]));
console.log('----->3' , arr1.flatMap(x => [[x * 2]]));
console.log('----->4' , arr1.map(x => [x * 2]).flat(1));
//输出结果
//----->1: [ [ 2 ], [ 4 ], [ 6 ], [ 8 ] ]
//----->2: [ 2, 4, 6, 8 ]
//----->3: [ [ 2 ], [ 4 ], [ 6 ], [ 8 ] ]
//----->4: [ 2, 4, 6, 8 ]
可以看出flatMap其实也就是前面两者,flat 和 map的结合,我们用flat和map也能实现flatmap的效果
//回调函数有三个值(当前值,当前值索引,数组对象本身)
const arr = [10, 8,4 , 6 , 9 , 3];
console.log(arr.filter(item => item > 5));
// 输出结果
//[10, 8, 6, 9 ]
该方法中,符合回调函数的执行就会返回标位 true ,最后会把所有标位 true的值返回为一个新数组,我们可以通过回调函数来筛选我们需要的值。
Object.keys(obj) —— 返回一个包含该对象所有的键的数组。
Object.values(obj) —— 返回一个包含该对象所有的值的数组。
Object.entries(obj) —— 返回一个包含该对象所有 [key, value] 键值对的数组。
const obj = {
a: 25,
b: 42,
c: 62,
d: 82,
};
for (const [key, value] of Object.entries(obj)) {
console.log(value*2);
}
for (const item of Object.keys(obj)) {
console.log('--------->key',item);
}
for (const item of Object.values(obj)) {
console.log('--------->values',item);
}
console.log('--------->',Object.entries(obj).map(([key, value]) => [key, value * 2]));
//输出结果
50
84
124
164
--------->key a
--------->key b
--------->key c
--------->key d
--------->values 25
--------->values 42
--------->values 62
--------->values 82
---------> [ [ 'a', 50 ], [ 'b', 84 ], [ 'c', 124 ], [ 'd', 164 ] ]
var alpha = ['a', 'b', 'c'];
var numeric = [1, 2, 3];
alpha.concat(numeric);
// result in ['a', 'b', 'c', 1, 2, 3]
迭代的方法非常的多,我们如何选择最合适的呢?一般我们先看我们需要操作的对象是数组还是对象,另外根据我们的需要,是否改变原函数,其次迭代在进行的过程中,是否需要中断。通过这几个条件,我们就能选择出适合我们需求的方法了。
还没写完~~~~还很多细节没补充,以及打算做成一张图的形式更加的直观,先发吧,写了几天腻了~