在 ECMAScript 中除了 Object
类型以外,Array
类型恐怕就是最常用的类型了。而且 ECMAScript 中的数组与其他多数语言中的数组有着相当大的区别,虽然 ECMAScript 数组与其他语言中的数组都是数据的有序列表,但与其他语言不同的是,ECMAScript 数组的每一项可以保存任何类型的数据。
别的就不多说了,本篇文章就是围绕 Array
类型的基础知识来进行总结
声明方式
数组最大长度约 42 亿 9 千万,超出则报错。
实例化构造函数时,若只传入一个数值类型参数,则意为声明一个 length
为该数值的空数组。
传入一个非数值类型 , 则意为声明一个只含有该元素的数组;传入多个值 , 则意为声明了一个由这几个值组成的元素的数组。
数组可以省去 new
简写为 Array(1,2,3)
,或者以数组字面量的形式声明,并且可以通过更改 length
属性来控制数组元素个数,数组中空元素值为 undefined
数组元素以逗号隔开,但最后一个值后不要跟,否则在 IE 等浏览器下会出现兼容问题,会多出一个 undefined
元素。
通过 length
属性也可以向数组末尾添加元素,相关用法如下:
var arr = new Array(1);
var arr2 = new Array('1');
var arr3 = new Array(1,2);
var arr4 = Array(1);
var arr5 = Array(1,2);
var arr6 = [1];
arr6.length = 5;
arr6[4] = 444;
arr6[arr6.length] = 'it is over';
console.log(arr);// output: [undefined × 1]
console.log(arr2);// output: ["1"]
console.log(arr3);// output: [1, 2]
console.log(arr4);// output: [undefined × 1]
console.log(arr5);// output: [1, 2]
console.log(arr6);// output: [1, undefined × 3, 444, "it is over"]
转换方法
调用 toString
方法 原理是每个元素调用 toString
,然后以 ,
隔开。
调用 toLocalString
,则是每个元素调用 toLocalString
方法,然后以 ,
隔开。
调用 join
方法,默认返回以 ,
隔开的字符串,若指定字符串,则以指定字符串隔开,相关的几个用法如下:
var aj = ['1',2,'333'];
console.log(aj.toString());// output: 1,2,333
console.log(aj.toLocaleString());// output: 1,2,333
console.log(aj.join('||'));// output: 1||2||333
console.log(aj);// output: ["1", 2, "333"]
栈方法
数组栈方法 模拟栈这种数据结构 Last In First Out
push
用于向数组末尾追加新元素, 返回值为更新数组后的长度
var colors = ['red','blue'];
var coLen = colors.push('green','yellow');
console.log(colors);// output: ["red", "blue", "green", "yellow"]
console.log(coLen);// output: 4
pop
用于剔除数组末尾的最后一个元素,返回值为剔除的那个元素,pop()
方法不可传入参数
var arrPop = [1,2,3,'44','55'];
var order = arrPop.pop();
console.log(arrPop);// output: [1, 2, 3, "44"]
console.log(order);// output: 55
队列方法
数组队列方法 模拟队列这种数据结构 First In First Out
shift
用于剔除数组前端的第一个元素,返回值为剔除的那个元素,shift()
方法不可传入参数,例如:
var queue = ['1111','22',333];
var front = queue.shift();
console.log(queue); //output: ["22", 333]
console.log(front); //output: 1111
unshift
用于向数组前端添加一个元素,返回值为新数组的长度,例如:
var usLen = queue.unshift('666');
console.log(queue);// output: ["666", "22", 333]
console.log(usLen);// output: 3
可以将这些方法一起使用模拟队列形式,例如:
queue.push('9999');// 向末尾添加元素
queue.shift();// 剔除第一个元素
console.log(queue);// output: ["22", 333, "9999"]
//或者是
queue.unshift('theFirst');// 向前端添加一个元素
queue.pop();// 剔除最后一个元素
console.log(queue);// output: ["theFirst", "22", 333]
重排序方法
reverse
可以对数组进行翻转,返回值是翻转后的新数组,此方法会改变原有数组,例如:
var rever = [1,30,2,30,40,'a',40,5,4,82];
var v = rever.reverse();
console.log(v);// output: [82, 4, 5, 40, "a", 40, 30, 2, 30, 1]
console.log(rever);// output: [82, 4, 5, 40, "a", 40, 30, 2, 30, 1]
sort方法若不传参,则将数组元素转换为字符串后 按字符串的编码大小 升序排列 此方法也会改变原有数组
var rever = [1,30,2,30,40,'a',40,5,4,82];
var q = rever.sort();
console.log(q);// output: [1, 2, 30, 30, 4, 40, 40, 5, 82, "a"]
console.log(rever);// output: [1, 2, 30, 30, 4, 40, 40, 5, 82, "a"]
冒泡排序
每次比较数组中相邻的两个元素,符合条件则互换位置,可以看做是:执行一次外层循环后,就取出了一个最大或最小值,将其 push
到数组末尾。
每轮外层循环结束后,数组后半部分多出一个最大或最小值,下轮循环的内层循环总次数减少 1,下次循环不会对该值进行操作。
也就是说,这种排序会针对所有元素进行重复比较换位置,直至循环次数减少为 1,用法如下:
var bubble = [49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,'cc',98,54,56,17,18,23,34,15,35,25,53,51];
var i = 0, l = bubble.length - 1, s = null;
for (;i < l;i++) {
for (var j = 0;j < l - i;j++) {
if (bubble[j] > bubble[j + 1]) { //此处的判断决定 将最大值还是将最小值push到数组末尾 也就是决定按升序还是按降序排列
s = bubble[j];
bubble[j] = bubble[j + 1];
bubble[j + 1] = s;
}
}
}
console.log(bubble);
//output: [4,5,12,13,27,34,38,49,49,62,64,65,76,78,97,99,"cc",15,17,18,23,25,34,35,51,53,54,56,98]
从结果可以看出,当数组含有字符串元素时,排序会被字符串分成两半分开排序,这是什么原因呢?因为当字符串与数值进行比较时,字符串会被 JS 引擎在底层隐式转换为数值,这里的字符串 cc
会被转换为 NaN
,而 NaN
与一切比较都返回 false
,所以这种结果是非常合理的。
瞎吉尔排序
下面这个是我接触冒泡排序之前写的 后来接触了冒泡排序才发现 我写的是什么鬼啊 干脆把这个算法叫做 瞎吉尔排序 吧 (逃
此算法虽然也通过比较元素排序 但不是比较相邻的元素 而且循环次数太多 没有冒泡排序效率高 下面介绍一下它的操作过程 :
-
将数组中的所有元素 依次与数组中的第i个数进行比较 取出最大或最小值
-
第一轮循环 依次将数组中所有元素与第一个元素比较 互换位置 循环完毕就能得出数组中的最大值 相当于将其unshift到数组第一个位置
-
第二次循环 将数组的第二大的值取出 unshift插入数组中 以此类推 … 最后一次循环unshift最后一个元素
var arr = [49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,'cc',98,54,56,17,18,23,34,15,35,25,53,51];
var i = 0, l = arr.length;
for(;i < l;i++){
for(var j = 0;j < l;j++){
if(arr[j] > arr[i]){ //此处的判断决定 是将最大值还是将最小值unshift到数组前端 也就是决定按降序还是按升序排列
n = arr[j];
arr[j] = arr[i];
arr[i] = n;
}
}
}
console.log(arr);
// output: [4,5,12,13,15,17,18,23,25,27,34,34,35,38,49,49,"cc",51,53,54,56,62,64,65,76,78,97,98,99]
可以看出瞎吉尔排序与冒泡排序略有不同 虽然也被字符串分开了 但是能够接着按顺序排列 不会被该字符串影响而重新排列
操作方法
concat
和 slice
这两个方法都有返回值,并且不会改变原有数组,用法如下:
//concat传入参数即复制一个数组副本,并加入值为该参数的新元素 若传入数组,则将数组拆分,再合并至新数组
var ccArr = [1,'22','33'];
var newccArr = ccArr.concat(123,[666, {name: 'Rihanna'}]);
console.log(newccArr); //output: [1, "22", "33", 123, 666, {name: "Rihanna"}]
console.log(ccArr); //output: [1, "22", "33"]
//slice 传入1个或2个number参数
//1个参数即从该参数下标位置开始截取至数组最后一个元素 包含该下标位置的元素和数组最后一个元素
var ssArr = newccArr.slice(1);
console.log(ssArr); //output: ["22", "33", 123, 666, {name: "Rihanna"}]
//2个参数即从参数1下标位置开始截取截取至参数2下标位置元素,不包含参数2下标位置的元素
var ssArr2 = newccArr.slice(1,2);
console.log(ssArr2); //output: ["22"]
//若参数为负数 则意为按照length+该负数 例如-1 意思就是length-1 即从最后一个元素开始截取
//若第二个参数比第一个参数小,则永远返回空数组 若参数为空 则返回原数组
var ssArr3 = newccArr.slice(-1,0);
var ssArr4 = newccArr.slice(-3,-1); // 意为从倒数第3个元素开始截取到最后一个元素 不包含最后一个元素
console.log(ssArr3); //output: []
console.log(ssArr4); //output: [123, 666]
splice
方法用于删除、替换数组元素,并且会改变原有数组,返回值是被删除的元素,若没有删除元素,则返回一个空数组,例如:
// 传入2个参数 即从第一个参数位置开始 删除共 第二个参数 项元素 删除的元素包括第一个参数位置的元素
var spArr = [66,'oo','cc',33,888,5555];
var spRes = spArr.splice(1,2);
console.log(spArr);// output: [66, 33, 888, 5555]
console.log(spRes);// output: ["oo", "cc"]
// 若不指定参数,则数组不会有任何改变
// 若指定1个参数 则从数组第一个元素开始 删除共 指定参数 项元素
var spArr2 = [66,'oo','cc',33,888,5555];
var spRes2 = spArr2.splice(3);
console.log(spArr2); //output: [66, "oo", "cc"]
console.log(spRes2); //output: [33, 888, 5555]
// 若指定3或3个以上个参数 即可有插入动作 第3个以后的参数都是要插入的元素 第1个参数为要操作的位置下标
var spArr3 = [66,'oo','cc',33,888,5555];
var spRes3 = spArr3.splice(1,2,'Marilyn','Britney');
console.log(spArr3);// output: [66, "Marilyn", "Britney", 33, 888, 5555]
console.log(spRes3);// output: ["oo", "cc"]
迭代方法
性能最高的是 for
,其次是 5 个迭代方法,性能最差的是 forEach
,所以应该尽量避免使用,相关用法如下:
var numbers = [1,2,3,4,5,6,7,8];
//every 数组中的每项元素都返回true则返回true,反之false
var everyResult = numbers.every(function(item, index, array){
return (item >1)
});
console.log(everyResult);// output: false
//some 与every相反 数组中只要有一个符合条件的元素 则返回true
var someResult = numbers.some(function(item, index, array){
return (item > 7)
});
console.log(someResult);// output: true
//filter 过滤方法 返回数组中符合条件的元素
var filterResult = numbers.filter(function(item, index, array){
return (item >7);
});
console.log(filterResult);// output: [8]
//map 地图方法 传入数组 对数组中每个元素进行操作 给出返回结果
var mapResult = numbers.map(function(item, index, array){
return item * 2
});
console.log(mapResult);// output: [2, 4, 6, 8, 10, 12, 14, 16]
//forEach 遍历方法 直接对数组每个元素进行操作 没有返回值
numbers.forEach(function(item, index, array){
console.log('key:'+index+',value:'+item);// output: key:0,value:1 key:1,value:2......
});
归并方法
reduce
和 reduceRight
的相关用法:
// reduce 归并数组 从左开始向右(数组末尾)归并,方法的第一个参数为上个参数,第二个参数为当前参数
var numbers = [1,2,3,4,5,6,7,8];
var sum = numbers.reduce(function (prev, cur, index, array) {
return prev - cur;
});
console.log(sum);// output: -34
// reduceRight 归并数组 从右开始向左(数组前端)归并,方法的第一个参数为上个参数,第二个参数为当前参数
var sub = numbers.reduceRight(function (prev,cur,index,array) {
return prev - cur;
});
console.log(sub);// output: -20
