结合《javascript高级程序设计》《javascript权威指南》《javascript语言精粹》作的一篇关于Array对象的全面解析。分为两篇:基础篇和扩展应用篇。javascript
数组是值的有序集合,每一个值称为一个元素,每一个元素在数组中有特定位置,以数字表示,称为索引,JavaScript中的数组是一个类数组的对象,虽然在性能上比真正的数组会慢,但它使用起来更方便。
前端
特色 | 说明 |
---|---|
元素类型任意性 | 数组元素能够是基础数据类型,对象,也能够是数组 |
动态性 | 根据须要它们会增加或缩减,而且在变化时无需从新分配内存空间 |
稀疏性 | 数组元素的索引不必定是连续的,它们之间能够有空缺, |
2.1 数组字面量方式 : 元素用逗号隔开便可。java
var empty = [];//建立空数组 var num = [1,2,3,4,5];//建立5个数值类型元素的的数组 var mix = [1,'jozo',true,[1,2],{1:'jozo'}];//建立任意类型元素的数组
2.2 构造函数方式 : 调用构造函数Array(),根据参数不一样,建立不一样的数组
a.不传递参数数组
var a = new Arry();//建立一个空数组,但咱们更经常使用下面的方式 var a = [];
b.传递一个数值参数,这个参数用来指定数组长度数据结构
var a = new Arry(5);// 建立了一个长度为5的数组
c.传递多个参数,用这些参数做为数组元素初始化数组。函数
var a = new Arry(1,'jozo',true,[1,2]);//构造函数的参数将会成为数组元素
3.1 添加性能
a.经过索引添加学习
var a = []; a[0] = 'jozo';//此时 a = ['jozo'] a[1] = 'blog';//此时 a = ['jozo','blog']
b.经过数组方法添加this
push(),concat(),splice(),unshift()
方法均可觉得数组添加元素,后面将会详细介绍。spa
3.2 删除
a.删除数组元素
var a = [1,2]; delet a[0];//删除第一个元素 console.log(a[0]);//undefined console.log(a[1]);//2 console.log(a.length);//2
能够看出,经过delete
运算符删除数组元素也有一些注意的地方。1.
原数组长度不变。2.
被删除的元素的值变为undefined
.3.
数组内的其余元素的索引没有改变。其实就是原数组变成了稀疏数组
。
splice(),pop(),shift()
数组方法也能够用于删除数组元素,后面讲解。
b.删除整个数组对象
第一种方式:直接操做数组对象(推荐用法) var a = [1,2]; a.length = 0; console.log(a);//输出: [] 第二种方式:改变变量的引用 (不算真正的删除) var a = [1,2]; a = []; console.log(a);//输出: []
其实上面的知识点不讲咱们都差很少都知道的。可是数组的一些方法属性咱们虽然知道可是却不会用,或是老是忘记该怎么用,由于它的方法属性也不少,咱们来分析下各个方法的特色:
经常使用方法 | 说明 | 返回值 | 影响原数组 |
---|---|---|---|
1.join() |
使用不一样的分隔符将数组转换成包含分隔符的字符串 | 转换后的字符串 | F |
2.reverse() |
颠倒数组元素的顺序 | 重排序的数组 | T |
3.sort() |
一般会接受一个比较函数将数组特定的顺序排序 | 重排序的数组 | T |
4.concat() |
将传递给该方法的每个参数添加到原数组中 | 修改后的数组副本 | F |
5.slice() |
获取当前数组中的一或多个元素建立一个新的数组 | 返回新的数组 | F |
6.splice() |
经过传递参数不一样,可实现数组的增删改 | 新的数组 | T |
7.push()/pop() |
两个数组的栈方法(后进先出),在数组的末尾增长或删除数组 | pop() 返回数组长度,push() 返回被删除的元素 |
T |
8.unshift()/shift() |
两个数组的堆方法(先进先出),在数组的前端增长或删除数组 | unshift() 返回数组长度,shift() 返回删除的元素 |
T |
3.1 join()
方法
将数组中的全部元素都转化为字符串连接在一块儿,能够指定一个可选的分隔符来分隔各个元素,若未指定分隔符,默认使用逗号:
var boys = ['jozo','jozo1','jozo2']; var newboy1 = boys.join(); var newboy2 = boys.join('+'); var newboy3 = boys.join(undefined); console.log(newboy1); // jozo,jozo1,jozo2 console.log(newboy2); // jozo+jozo1+jozo2 console.log(newboy3); // jozo,jozo1,jozo2 console.log(boys); // ["jozo", "jozo1", "jozo2"]
从上面的代码能够看出一些问题:1.
给join()
方法传递undefined
,也会默认使用逗号分隔符,可是IE7及一下版本会直接用'undefined'
做为分隔符。2.join()
方法并无改变原数组。
3.2 reverse()
方法
将数组元素颠倒顺序(注意:并非从大到小或者是从小到大
),返回逆序的数组,这个方法直接对原数组中排序。
var a = [1,3,2]; console.log(a.reserse());// [2,3,1] 只是颠倒顺序,不是按大小排序 console.log(a);//[2,3,1] 改变了原数组
这个方法快速直观明了,但不够灵活,不少时候咱们须要特定的排序,因此有了下面的更灵活的方法。
3.3 sort()
方法
默认状况下,sort()方法按从小到大的排序,可是若是是数值,sort()方法会调用每一个元素的toString()方法转换为字符串后再比较:
var num = [1,5,10,15]; console.log(num.sort()); //[1,10,15,5] 按照字符串比较。 var num = ['jozo','c','b','a']; console.log(num.sort()); //['a','b','c','jozo'] 按照字符串比较。
默认的sort()方法以字母表顺序进行排序,这有时也不是最佳方案,所以咱们能够传递一个函数类型的参数做为比较函数,改变排序方式,以便咱们肯定哪一个值在前面。
比较函数:接受两个参数,函数的返回值决定数组的排序方式。
返回值 | 排序方式 |
---|---|
负数 | 从小到大 |
正数 | 从大到小 |
0 | 顺序可有可无 |
看下代码:
// 为了直观一点,写个罗嗦的比较函数 var compare = function(a,b){ if(a < b){ return -1; }else if(a > b){ return 1; }else{ return 0; } }; var num1 = [1,5,10,15]; console.log(num1.sort(compare)); //[1,5,10,15] 从小到大 var num2 = ['jozo','c','b','a']; console.log(num2.sort(compare)); //['a','b','c','jozo'] 从小到大 // compare()函数能够改进下: //从小到大的比较函数 var compare = function(a,b){ return a - b; }; //从大到小的比较函数 var compare = function(a,b){ return b - a; }; //或者直接给sort()方法传递一个匿名比较函数: num.sort(function(a,b){return a -b}); // 推荐用法
3.4 concat()
方法
这个方法先会建立当前数组的一个副本,而后将收到的参数添加到副本数组的末尾,返回从新构建的数组。
1.
当没有传递参数时,只是返回当前数组的一个副本。
var a = [1,2]; b = a.concat(); console.log(b);//[1,2] a 的副本 console.log(a);//[1,2]; a 未改变
2.
当传递的参数为非数组时,将会把每一个参数添加到副本中
var a = [1,2]; b = a.concat(3,4); console.log(b);//[1,2,3,4] 在a的副本上添加 console.log(a);//[1,2]; a 未改变
3.
当传递的参数是数组时,将会把数组的每个元素添加到副本中。
var a = [1,2]; b = a.concat([3,4]); console.log(b);//[1,2,3,4] 在a的副本上添加 console.log(a);//[1,2]; a 未改变 //来看看参数的另外一种形式 var a = [1,2]; b = a.concat([3,4,[5,6]]); //数组的数组 console.log(b);//[1,2,3,4,[5,6]] //数组的数组直接添加到副本 console.log(a);//[1,2]; a 未改变
3.5 slice()
方法
这个方法返回指定数组的一个片断或子数组,接受一个或两个参数。
1.
一个参数 :返回该参数指定位置(包含)到数组末尾的元素的新数组
var a = [1,2,3,4,5]; a.slice(0);// 返回 [1,2,3,4,5] a.slice(1);// 返回 [2,3,4,5] a.slice(7);// 返回 [] 参数超过数组索引,返回空数组 a.slice(-1);//返回 [5] 用数组长度-1 至关于slice(4); console.log(a);//返回 [1,2,3,4,5] 原数组不变
2.
两个参数 :参数做为始末位置,但不包含第二个参数指定的位置。
var a = [1,2,3,4,5]; a.slice(0,4);// 返回 [1,2,3,4] a.slice(1,4);// 返回 [2,3,4] a.slice(1,7);// 返回 [2,3,4,5] 参数超过数组索引,则到数组末尾 a.slice(1,-1);//返回 [2,3,4] 用数组长度-1 至关于slice(1,4); a.slice(1,-7);//返回 [] 当结束位置小于起始位置,返回空数组 console.log(a);//返回 [1,2,3,4,5] 原数组不变
3.6 splice()
方法
这个数组恐怕是数组里最强大的方法了,它有多种用法,主要用途是向数组中部插入元素,请不要和上面的slice()方法混淆了,这是两个彻底不一样的方法。由参数的不一样,可实现下列三种方法:
1.
删除 :指定一个或两个参数,第一个参数是删除的起始位置,第二个参数是要删除的元素个数,若省略第二个参数,则从起始位置删除至末尾:
var a = [1,2,3,4,5]; a.splice(3,2);//返回 [4,5] 从索引3开始,删除2个元素,此时 a = [1,2,3] a.splice(1);// 返回 [2,3] 此时 a = [1]
2.
插入:指定3个及以上个参数,前两个参数和上面的一致,第二个参数通常为0
,后面的参数表示要插入的元素:
var a = [1,2,3,4,5]; a.splice(4,0,6,7);//返回 [] 从索引4开始,删除0个元素,此时 a = [1,2,3,4,5,6,7] //下面这种状况又和concat()不一样,直接插入数组而非数组元素 a.splice(4,0,[6,7]);//返回 [] 从索引4开始,删除0个元素,此时 a = [1,2,3,4,5,[6,7]]
3.
更新:指定3个及以上个参数,前两个参数和上面的一致,第二个参数指定要删除的元素个数,后面的参数表示要插入的元素:
var a = [1,2,3,4,5]; a.splice(3,2,6,7);//返回 [4,5] 从索引3开始,删除2个元素,此时 a = [1,2,3,6,7]
3.7 push()/pop()
方法
补充下数据结构的知识,栈是一种LIFO(Last-In-First-Out,后进先出)
的数据结构,也就是最新添加的项最先被移除。而栈中项的插入和移除只发生在栈顶部。数组的push(),pop()
方法就为数组实现了相似栈的功能:
1.push():
该方法能够接受任意数量,任意类型的的参数,并将它们添加至数组的末尾(栈顶),最后返回修改后的数组的长度
。
var a = [];// 建立空数组 var lng = a.push(1,2,3);// 添加数组元素 console.log(a);// 输出:[1,2,3] console.log(lng);// 输出:3 返回数组长度3 var lng2 = a.push(4,[5,6]);// console.log(lng2); // 输出:5 返回数组长度5 console.log(a);//输出:[1,2,3,4,[5,6]]
2.pop() :
相反,该方法删除数组的最后一个元素,减少数组长度,并返回删除的元素。不带参数。
var a = [1,2,3]; var last= a.pop();// 删除数组最后一个元素 console.log(a);// 输出:[1,2] console.log(last);// 输出:3 被删除的元素是 3
能够看出,这两个方法都是直接修改原数组。
3.8 unshift()/shift()
方法
上面提到了栈的数据结构,这里再提一个队列的数据结构,这是一种FIFO(First-In-First-Out,先进先出)
的数据结构,队列添加元素是在末端,删除是在前端。不少同窗就会猜想了,unshift()
就是在末端添加元素,shift()
就是在前端删除元素,其实否则:
1.shift():
用于在前端删除数组元素,返回被删除的元素,与push()
方法结合即是一对队列方法。
var a = [1,2,3]; a.push(4,5);//此时 a = [1,2,3,4,5] var start = a.shift();//此时 a = [2,3,4,5] 删除最前端的元素 console.log(start);// 1 返回删除的元素
2.unshift():
用于在前端添加元素,返回修改后的数组的长度,与pop()方法结合即是一对反操做的队列。
var a = [1,2,3]; a.unshift(4,5);//此时 a = [4,5,1,2,3] 在前端添加元素 var end= a.pop();//此时 a = [4,5,1,2] console.log(end);// 3 返回删除的元素
这两个方法一样都是直接修改原数组。
ECMAScript定义了9个操做数组的数组方法:
遍历:forEach()
映射:map()
过滤:filter()
检测:every(),some()
简化:reduce(),reduceRight()
搜索:indexOf(),lastIndexOf()
每一个方法都接受两个参数:1.
要在每一个数组元素上运行的函数;2.
运行函数的做用域对象 -- this指向 (可选参数)
第一个参数--函数又可传递三个参数(简化和搜索方法除外)
,分别表明:1.
每一个数组元素的值;2.
元素的索引;3.
数组自己
注意:全部这些方法都不会修改原始数组,可是传递的函数是能够修改的。
4.1 forEach()
该方法对数组的每一项运行给定的函数。这个方法没有返回值。
var nums = [1,2,3]; var sum = 0; nums.forEach(function(value){sum += num;}); //没有对原数组进行修改 console.log(sum); // 6 1+2+3 nums.forEach(function(value,i,ary){ary[i] = value +1;}); //对数组进行了修改 console.log(nums);//[2,3,4]
4.2 map()
该方法对数组的每一项运行给定的函数,返回每次函数调用的结果组成的数组。
var nums = [1,2,3]; var squer = nums.map(function(value){return value*vlaue}); console.log(squer); // [1,4,9] console.log(nums);// [1,2,3]
注意:这可能看起来有点像forEach()方法,但细看会发现 该方法有返回值,而前者没有,并且返回值是数组,这个数组是新数组,并无对原始数组进行修改。若是原始数组是稀疏数组,返回的也是相同方式的数组,具备相同的长度和相同的缺失元素。
4.3 filter()
该方法对数组的每一项运行给定的函数,返回该函数会返回true的项组成的数组。
var a = [1,2,3,4,5]; smallValue = a.filter(function(value){return value < 3;});// [1,2]
注意:filter()会跳过稀疏数组中缺乏的元素,他的返回数组老是稠密的。下面的方式能够压缩稀疏数组的看空缺:
var a = [1,,3,,5];//有两个空缺元素 Var uglify = a.filter(function(){return true;}); //[1,3,5]
还能够过滤undefined和null的元素:
var a = [1,undefined,3,,null,5];//有两个空缺元素 Var uglify = a.filter(function(value){ return value != undefined && value != null; }); //[1,3,5]
4.4 every(),some()
every():
对数组的每一项运行给定的函数,若是该函数对数组的每一项都返回true,则返回true,注意是每一项
,有一项为false则为false.
var nums = [1,2,3,4,5]; var bigresult = nums.every(function(value){return value > 2}); // false 不全大于2 var result = nums.every(function(value){return value > 0}); //true 所有大于0
some():
对数组的每一项运行给定的函数,若是该函数对数组的任一项
返回true,则返回true。
var nums = [1,2,3,4,5]; var bigresult = nums.every(function(value){return value > 2}); // true 有大于2的元素 var result = nums.every(function(value){return value < 0}); //false 所有大于0
注意:在数组是空数组时,every()返回true,some()返回false
4.5 reduce(),reduceRight()
这两个方法都会迭代数组的全部项,而后构建一个最终的返回值。reduce()从数组的第一项开始,逐个遍历到最后;reduceRight()从数组的最后一项开始,逐个遍历到第一项。
这两个方法都是接收两个参数,一个是在每项上调用的函数,另外一个是做为遍历的初始值。调用的函数又接收四个参数,分别是:前一个值,当前值,索引,数组对象。这个函数的返回值都会自动做为下一次遍历的函数的第一个参数。若未指定初始值,第一次遍历发生在数组的第二项上,所以第一个参数就是数组第一项,第二个参数就是数组的第二项。咱们来个求和运算:
var nums = [1,2,3,4,5]; nums.reduce(function(pre,cur,index,ary){return pre + cur;}); // 15 //指定初始值,则第一个参数就是初始值,第二个参数就是数组第一项 nums.reduce(function(pre,cur,index,ary){return pre + cur;},10); 25
在简单的数字元算上,reduce()和reduceRight()除了顺序不一样,其余的彻底相同。
4.6 indexOf(),lastIndexOf()
这两个方法都接受两个参数:要查找的项,查找起点位置的索引(可选);indexOf()从数组头部开始检索,lastIndexOf()则从数组尾部向前开始检索。
两个方法都都返回找到的元素的第一次出项的位置(索引),在没有找到的状况下返回 -1 。
要注意的是:在检索时会与数组的每一项进行全等的比较,也就是必须严格相等(===)。
var nums = [1,2,3,4,5,4,3,2,1]; console.log(nums.indexOf(3)); // 2 索引为2 console.log(nums.lastIndexOf(3)) // 6 从后面开始找,索引为6; console.log(nums.indexOf(3,3)); // 6 从位置3开始向后找 console.log(nums.lastIndexOf(3,3)) // 2 从位置3开始向前找 console.log(nums.indexOf(6)); // -1 没有找到 var class= {name : 'ruanjian'}; var students = [{name : 'jozo'}]; console.log(students.indexOf(class)); //false 非严格相等(不是同一个对象) var school = [class]; console.log(school.indexOf(class);); //true 严格相等(同一个对象)
结合高级程序设计与权威指南两本书,内容比较多,写了好长,写的过程当中有种以为不必的感受,可是写完以后就会以为颇有价值,至少对我来讲。不是我不会,而是记得不深入,从新书写一遍以后感受对数组这东西比较透彻了。我也建议各位多作一个学习总结,若有不正确的,请提醒修正。谢谢。下一篇文章继续介绍数组!关于ES6的一些扩展以及数组一些应用。