从头开始复习js之让你彻彻底底搞清楚数组
栏目: JavaScript · 发布时间: 5年前
内容简介:关于数组这一块,从开始写项目开始就一直在用,但是基本都没有整理过,怎么说呢?既然在复习这个东西,那我今天正好在复习这个数组,就集中整理一下在实际开发中用到频率最高的数据吧。es5中定义了22个数组的方法,这22个方法的使用频率基本贯穿整个前端开发,如果你想进入前端,这22个应该成为你的本能反应。下面就针对这22个,我来简单做一下代码的实例吧:关于数组定义一般有两种方式:
关于数组这一块,从开始写项目开始就一直在用,但是基本都没有整理过,怎么说呢?既然在复习这个东西,那我今天正好在复习这个数组,就集中整理一下在实际开发中用到频率最高的数据吧。
一、 es5中的数组方法
es5中定义了22个数组的方法,这22个方法的使用频率基本贯穿整个前端开发,如果你想进入前端,这22个应该成为你的本能反应。下面就针对这22个,我来简单做一下代码的实例吧:
1.1、 数组定义
关于数组定义一般有两种方式:
- new字符
- 数组字面量
- 数组的清空
具体的定义如下:
var testArray = new Array(); var testArray1 = [1,2,3,4,5]; 复制代码
额,这里重点提一下数组的清空,我建议使用:
var testArray = []; 复制代码
1.2、 数组检测
在es5里面检测数据类型是不是数组的方式主要有两个,length主要用来获取数组的长度:
- instanceof:判断构造函数
- isArray
- length:返回数据内元素的个数
具体的代码如下:
var array = [1,2,3,4,5]; var object = { key:1,value:"hello"}; console.log(array instanceof Array); // true console.log(object instanceof Array); // false console.log(Array.isArray(array)); // true console.log(Array.isArray(object)); // false console.log(array.length) // 5 复制代码
1.3、 数组转化成字符串
数据转化成字符串一般有三种方式:
- toLocaleString
- toString
- join
来看下面一段代码:
console.log(array.toString()); // 1,2,3,4,5 console.log(array.toLocaleString()); // 1,2,3,4,5 console.log(array.join("")); // 12345 console.log(array.join("&&")); // 1&&2&&3&&4&&5 console.log(array.join()); // 1,2,3,4,5 复制代码
首先 toString 和 toLocaleString 是将数组直接转化成 String ,中间用逗号分隔。(到现在为止我都不知道两者在Array中有什么区别,我自己做实验只在Date中发现了一点异常。)
其次是join:数组元素先被转换为字符串,再将这些字符串用 separator 分割连接在一起。如果没提供分隔符,将一个逗号用作分隔符。
1.4、 数组的添加和删除
数组的增删操作的属性一共下面几种:
- push:在数组的最末尾添加元素
- pop:在数据的最末尾删除元素
- unshift: 在数组的最前面添加一个元素
- shift: 删除数组的最前面一项
来看下面一段代码:
var array = [1,2,3,4,5]; array.push(999); // [ 1, 2, 3, 4, 5, 999 ] array.pop(); // [ 1, 2, 3, 4, 5 ] array.unshift(999); // [ 999, 1, 2, 3, 4, 5 ] array.shift(); // [ 1, 2, 3, 4, 5 ] 复制代码
1.5、 数组的排序
关于数组的排序,主要有两个方法:
- reverse 翻转数组
var array = [1,2,3,4,5]; array.reverse(); // [ 5, 4, 3, 2, 1 ] 复制代码
- sort //数组中按元素来排序,默认是按照首个字符的Unicode编码排序,所以默认是从小到大排序。
sort方法接收两个参数,第一个是数组,第二个参数如果存在,就会按照第二个函数的返回值来排序,如果不存在 缺省值是从小到大。来看下面一段代码:
array.sort() // [ 1, 2, 3, 4, 5 ] array.sort((a,b)=>{ return b-a; }); console.log(array); // [ 5, 4, 3, 2, 1 ] 复制代码
关于数组的 排序 这一块的源码呢,之前我有看过一部分,我发现,在源码中数组长度小于23的时候采用的是插入排序,反之则用的是快速排序。(甚至命名都是InsertionSort,QuickSort),关于排序的实现方式,可以去看一下 我之前写的排序的文章来复习一下,我觉得我自己写的还比较好理解的。
1.6、 数组元素的裁剪/缝补
- concat: 合并数组
var array1 = [1,2,3]; var array2 = ["1","2","3"]; console.log(array1.concat(array2)); // [1,2,3,"1","2","3"]; 复制代码
- slice: 数组截取
var arr = [1, 2, 3, "a", "b", "c"]; console.log(arr.slice(3)); //["a", "b", "c"] console.log(arr.slice(0,3)); // [1, 2, 3] console.log(arr.slice(0,10)); // [1, 2, 3, "a", "b", "c"] console.log(arr.slice(7,10)); //[] console.log(arr.slice(-2)); // ["b", "c"] console.log(arr.slice(3,0)); // [] console.log(arr); // 复制代码
这里值得我们注意的点是: 1、 slice默认接收两个参数,slice(start,end),表示从开始截取的位置和截取结束的位置。 2、 如果只填写一个参数,是从该位置开始向后截取,直到末尾。 3、 如果只填写一个负数参数的话,是从末尾开始向前截取。 4、 如果第一个参数比后面大,返回值为空数组。 5、 如果截取的开始位置大于数组长度返回空数组。 6、 如果截取的结束位置大于数组的长度,返回开始截取到数据的末尾的数列。
- splice:数组的删除,删除,增加的数据
首先来看一个基础的例子
var arr = [1, 2, 3, "a", "b", "c"]; arr.splice(2);// [ 1, 2 ] arr.splice(0,1); // [2] 复制代码
然后我们再来看一个带插入的例子:
var arr1 = [1, 2, 3, "a", "b", "c"]; arr1.splice(3,2,"hello","world");// [ 1, 2, 3, 'hello', 'world', 'c' ] 复制代码
值得我们注意的点是: 1、 splice的参数含义是:splice(开始操作的索引值,删除几项,后面的n项代表从开始操作的索引值开始插入的项) 2、 如果只传入一个参数,默认返回0到指定参数的值
1.7、 数组的查找
- indexof/lastIndexOf,从数组的前/后查数据的索引 来看下面一个例子
var arr = [1, 2, 3, "a", "b", "c"]; console.log(arr.indexOf("b")); // 4 console.log(arr.lastIndexOf("b")); // 4 console.log(arr.indexOf("es")); // -1 复制代码
这里值得注意的是:indexOf是去查询元素第一次出现的索引,而lastIndexOf是去查询元素最后一次出现的索引。
- every 如果数组内的每一个元素都满足一个要求,就返回true
var arr = [ 1, 2, 3, 4, 5 ]; arr.every((item,index,array)=>{ if(item>0) return true; return false; }); //true arr.every((item,index,array)=>{ if(item>3) return true; return false; }); // false 复制代码
从上面的代码,我们可以看出: 1、 every接收一个函数,函数的返回参数有三个,遍历的项,当前遍历的index和数组本身 2、 当函数的全部项都返回true的时候every才成立;有一项不返回true,every将不会成立。
- some:如果数组内存在一个元素满足回调函数内的要求,就返回true 关于some可以跟every做对比记忆。
var arr = [ 1, 2, 3, 4, 5 ]; arr.some((item,index,array)=>{ if(item>4) return true; return false; }); //true arr.some((item,index,array)=>{ if(item>7) return true; return false; }); // false 复制代码
从上面的代码,我们可以看出 1、 some接收一个函数,函数的返回参数有三个,遍历的项,当前遍历的index和数组本身 2、 当函数的全部项都返回false的时候some就会返回false;有一项返回true,some都将成立。
- filter:返回数组内满足回调函数的元素 同样这个函数也能对比和上面两个记忆。来看下面一段代码。
var arr = [ 1, 2, 3, 4, 5 ]; arr.filter((item,index,array)=>{ return item>3; }); //[ 4, 5 ] 复制代码
从上面可以看出来,filter将会筛选出满足条件的数列出来。
- forEach: 数组遍历 这个就不做演示了,主要是遍历,跟for一样
1.8、 数组的重装和合并
- map:对于数组的每一项都用函数进行重组,如果不return,返回undefined 关于map方法,其实在开发中用到的真的特别多,来看下面一个例子:
var arr = [ 1, 2, 3, 4, 5 ]; arr.map((item,index,array)=>{ if(item>3){ return {key:"小于三的数",value:item} } return {key:"大于二的数",value:item} }); //[ { key: '大于二的数', value: 1 }, // { key: '大于二的数', value: 2 }, // { key: '大于二的数', value: 3 }, // { key: '小于三的数', value: 4 }, // { key: '小于三的数', value: 5 } ] 复制代码
从上面我们可以得出,map方法是将每一项的返回值重新组装成一个新的数组,如果没有return会返回。
- reduce/reduceRight:从左/右开始对元素的累加。
var arr = [ 1, 2, 3, 4, 5 ]; var result1 = arr.reduce((sum,item)=>{ return sum*10 + item; }); var result2 = arr.reduceRight((sum,item)=>{ return sum*10 + item; }); console.log(result1) console.log(result2) 复制代码
二、 es5后新增的数组方法
2.1、 数组的创建和初始化
关于from和of,其实可能遇到call和bind,可以看看之前我的文章。
- Array.from 我们来看一组代码:
var obj = { "0":"a", "1":"b", "2":"c", length: 3 } var obj1 = { "0":"a", "1":"b", "2":"c", } var obj2 = { "a":"a", "b":"b", "c":"c", length: 3 } console.log(Array.from(obj)); // [ 'a', 'b', 'c' ] console.log(Array.from(obj1)); // [] console.log(Array.from(obj2)); // [ undefined, undefined, undefined ] 复制代码
从上面的代码,我们可以清楚的发现: 1、 Array.from是需要length属性的,如果没有length属性,将返回空数组 2、 Array.from操作对象的属性名一定是数字,不然会返回undefined。
- Array.of
Array.of主要用于将一组值转化成数组
Array.of(3, 11, 8) // [3,11,8] Array.of(3) // [3] Array.of(3).length // 1 复制代码
Array.of的创建主要是为了弥补Array方法的一些小漏洞,例如:
Array() // [] Array(3) // [, , ,] Array(3, 11, 8) // [3, 11, 8] 复制代码
- fill
fill方法的作用是,将给的定值填充到数组中,来看下面一组代码:
['a', 'b', 'c'].fill(7); // [7, 7, 7] new Array(3).fill(7) // [7, 7, 7] ['a', 'b', 'c'].fill(7, 1, 2) // ['a', 7, 'c'] let arr = new Array(3).fill({name: "jkb"}); arr[0].name = "klivitam"; console.log(arr); // [{name: "klivitam"}, {name: "klivitam"}, {name: "klivitam"}] 复制代码
从上面的代码我们可以发现: 1、 fill接收三个参数,fill(填充的值,填充的开始值,填充的结束值) 2、当只存在一个参数时,默认将全部数组都填充给列表项 3、 当填充的值是对象的时候,我们是填充的对象的指针,所以这是一个坑 在用的时候请谨慎哦。
2.2、 数组的查找
- find/findIndex
let data = [1,2,3,4,5]; let obj = { name:"klivitam", number:1 } let result1 = data.find((it,index,arr)=>{ return it>3; }) let result2 = data.findIndex((it,index,arr)=>{ return it>3; }) let result3 = data.find((it,index,arr)=>{ return it>10; }) let result4 = data.find(function(v){ return v>this.number; },obj) console.log(result1) // 4 console.log(result2) // 3 console.log(result3) // undefined console.log(result4) // 2 复制代码
从面的代码我们可以发现: 1、 find和findIndex分别都接收两个参数,第一个是函数,第二个是对象,前一个函数的this指针指向后一个对象 2、 find和findIndex只能发现数组内出现的第一个值,如果没有发现返回undefined
- includes
let data = [1,2,3,4,5,NaN]; console.log(data.includes(1)); // true console.log(data.includes(1,2)) // false console.log(data.includes(NaN)) // true console.log(data.indexOf(NaN)) // -1 复制代码
从面的代码我们就可以清楚的发现: 1、 includes方法接收两个参数,第一个是搜索的值,第二个是从数据的第几项开始搜索 2、 indexOf无法查找到NaN的位置,但是includes可以。
- entries/keys/values
let data = [1,2,3]; for (let index of data.keys()) { console.log(index); } // 0 // 1 // 2 for (let elem of data.values()) { console.log(elem); } // 1 // 2 // 3 //这里使用了解构赋值 for (let [index, elem] of data.entries()) { console.log(index, elem); } // 0 1 // 1 2 // 2 3 复制代码
2.2、 数组的操作
- 扩展运算符 扩展运算符(spread)是三个点(...)。它将一个数组转为用逗号分隔的参数序列。具体的事例代码如下:
console.log(...[1, 2, 3]); // 1,2,3 console.log((...[1, 2,3])); // Uncaught SyntaxError: Unexpected number Math.max(...[14, 3, 77]) // 77 const [...[1,2,3]] = a1; // 1,2,3 [...['a', 'b'], ...['c'], ...['d', 'e']]; // [a,b,c,d,e] [...'hello'];// [h,e,l,l,0] 复制代码
关于扩展运算符这一块,我不想过多的来讲解,其实很多东西 还是要靠自己在写代码的时候来总结,关于有些技术,我也不知道哪里好,但是遇到问题了 我就想用。
- copyWithin
[1, 2, 3, 4, 5].copyWithin(0, 3); // [4, 5, 3, 4, 5] // 将3号位复制到0号位 [1, 2, 3, 4, 5].copyWithin(0, 3, 4) // [4, 2, 3, 4, 5] [1, 2, 3, 4, 5].copyWithin(0, -2, -1); // [4, 2, 3, 4, 5] [].copyWithin.call({length: 5, 3: 1}, 0, 3)// {0: 1, 3: 1, length: 5} 复制代码
从上面的代码我们可以发现: 1、 数组实例的copyWithin方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组。 2、 该方法接受三个参数,分别是从该位置开始替换数据,从该位置开始读取数据,到该位置前停止读取数据。
- flat/flatMap
[1, 2, [3, 4]].flat(); // [1, 2, 3, 4] [1, 2, [3, [4, 5]]].flat(); // [1, 2, 3, [4, 5]] [1, 2, [3, [4, 5]]].flat(2); // [1, 2, 3, 4, 5] [1, [2, [3]]].flat(Infinity)// [1, 2, 3] [1, 2, , 4, 5].flat() // [1, 2, 4, 5] [2, 3, 4].flatMap((x) => [x, x * 2])// [2, 4, 3, 6, 4, 8] 复制代码
从上面的代码我们可以发现:
- flat的作用是:用于将嵌套的数组“拉平”,变成一维的数组。flapmap的作用是首先将元素进行一次map方法,然后再进行一次flat方法。
- flat方法接受一个参数,代表拉伸的层数,也可以用Infinity,拉平所有的嵌套数组
- flat再拉平数组的时候,然后遇到空位会跳过该空位
三、数组的空位
前面在讲解flat的时候,我们提到了一个空位的概念,结合开发以及阮大神在博客中的总结,我也更深的了解到空位的差异。 首先我们来看一段代码:
[,'a'].forEach((x,i) => console.log(i)); // 1 ['a',,'b'].filter(x => true) // ['a','b'] [,'a'].every(x => x==='a') // true [1,,2].reduce((x,y) => x+y) // 3 [,'a'].some(x => x !== 'a') // false [,'a'].map(x => 1) // [,1] [,'a',undefined,null].join('#') // "#a##" [,'a',undefined,null].toString() // ",a,," 复制代码
这里我们就可以明显的看到在es5中对空格的处理方法就已经出现了分歧。
- forEach(), filter(), reduce(), every() 和some()都会跳过空位。
- map()会跳过空位,但会保留这个值
- join()和toString()会将空位视为undefined,而undefined和null会被处理成空字符串。
那我们来看es6呢?来看下面一段代码:
Array.from(['a',,'b'])// [ "a", undefined, "b" ] [...['a',,'b']] // [ "a", undefined, "b" ] [,'a','b',,].copyWithin(2,0) // [,"a",,"a"] new Array(3).fill('a') // ["a","a","a"] let arr = [, ,]; for (let i of arr) { console.log(1); } // 1 // 1 [...[,'a'].entries()] // [[0,undefined], [1,"a"]] [...[,'a'].keys()] // [0,1] [...[,'a'].values()] // [undefined,"a"] [,'a'].find(x => true) // undefined [,'a'].findIndex(x => true) // 0 复制代码
从上面代码我们可以发现:
- Array.from、扩展运算符、entries()、keys()、values()、find()和findIndex()方法会将数组的空位,转为undefined
- fill()会将空位视为正常的数组位置。
- copyWithin()会连空位一起拷贝。
- 上面代码中,数组arr有两个空位,for...of并没有忽略它们。如果改成map方法遍历,空位是会跳过的。
其实用代码演示了这么多,无非就是想说明一件道理:空位不同的方法对其的处理方式不同 如果你能够记得所有方法的处理方式,那你大可以任意使用 如果不行 还是尽量避免出现空位吧
说在最后
这篇文章写的我很是烦躁呀,主要总结下来东西实在是太多了,但是怎么说呢?还是有很大的好处的,比如数组的空位这个之前我就只知道基础的几种,剩下的 我基本都没有去验证,现在抽时间把这些东西全部验证了一遍感觉印象也加深了不少。好了 差不多一点钟了,去睡觉了 (说好的从这周起开始睡美容觉的)
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
程序员的数学思维修炼(趣味解读)
周颖 / 清华大学出版社 / 2014-4-1 / 45.00元
本书是一本专门为程序员而写的数学书,介绍了程序设计中常用的数学知识。本书门槛不高,不需要读者精通很多高深的数学知识,只需要读者具备基本的四则运算、乘方等数学基础知识和日常生活中的基本逻辑判断能力即可。本书拒绝枯燥乏味的讲解,而是代之以轻松活泼的风格。书中列举了大量读者都很熟悉,而且非常有趣的数学实例,并结合程序设计的思维和算法加以剖析,可以训练读者的数学思维能力和程序设计能力,进而拓宽读者的视野,......一起来看看 《程序员的数学思维修炼(趣味解读)》 这本书的介绍吧!