1. 参考
  2. 速查表
  3. 实例化(创建)数组
  4. 访问数组元素
    1. slice
  5. 数组长度
  6. 判断
    1. 判断对象是否是数组
    2. 判断元素是否在数组
  7. 添加元素
    1. push
    2. unshift
    3. concat
    4. splice
  8. 删除元素
    1. pop
    2. shift
  9. 数组的拷贝(复制)
    1. 浅拷贝
    2. 深拷贝
  10. 数组转字符串
    1. toString
    2. join
  11. 字符串转数组
  12. 数组的遍历
    1. for
    2. for in
    3. for of
  13. 数组排序
    1. sort
    2. 翻转数组
    3. 随机排序

JavaScript Array

数组是一种数据结构,内含一组有序元素.在js中,数组也是对象

参考

Object.prototype.toString方法的原理 紫云飞
How can I shuffle an array? stackoverflow
获取两个数间的随机数 stackoverflow

速查表

实例化(创建)数组

有两种方式创建数组
1 通过Array构造函数创建数组
new Array()
new Array(length | element1, element2...)

//不传入参数,返回空数组
var arr = new Array();
console.log(arr) //[]

//传入单个整数,返回该整数长度的空数组
var arr = new Array(3)
console.log(arr); //[empty × 3]

//传入单个非数字/多个对象,返回包含这些对象的数组
var arr = new Arry('3');
console.log(arr); //["3"]

注意 传入单个非整数数字会报错

var arr = new Array(3.1)
console.log(arr); //RangeError: Invalid array length

2 通过声明数组自面量的方式创建数组对象
[] // 创建一个空数组
[element1, element2,...] //创建一个数组,内含元素 element1 element2 ...

var array = [1, 2, 3]
console.log(array) // [1, 2, 3]

字面量(literal)是一种值的表示方法.看到该值,就能立刻明白该值是什么对象
1 true null {num:1}都是一种字面量
例如 数字17有很多种表示方法

var num = 17 // 十进制
var num = 0b10001 // 2进制
var num = 0x11 // 16进制

访问数组元素

可用一对中括号获取/设置数组元素
array[index]
index 数组元素的索引(),从0开始计数

// 获取数组的第一个元素
var arr = [1, 2, 3]
arr[0] // 1

也可用中括号修改指定的数组元素

// 更改数组的第一个元素
arr[0] = 'a'
console.log(arr) //  ["a", 2, 3]

slice

获取一段数组元素,返回该段元素组成的新数组
array.slice() //如果参数为空,则返回包含所有元素的新数组
array.slice(startIndex)
array.slice(startIndex, endIndex)

var arr = [1, 2, 3];
arr.slice(0) // [1, 2, 3]
arr.slice(1) //  [2, 3]

指针也可以从后向前计数,从-1开始

//获取倒数第一个元素
arr.slice(-1) // [3]

注意 所获元素不包含endIndex

//不包含最后一个元素
arr.slice(0,2) // [1, 2]
arr.slice(0,-1) //[1, 2]

数组长度

可用length属性获得/更改数组长度
array.length //返回数组长度
array.length = num //设置数组长度

var arr = [1, 2, 3];
arr.length // 3

arr.length = 10
console.log(arr) //  [1, 2, 3, empty × 7]
//更改数组长度为1,相当于除第一个外的数组元素都被删除了
arr.length = 1
console.log(arr) //[1]

判断

判断对象是否是数组

Object.prototype.toString.call(object) === '[object Array]'
把toSring方法中的this指向需判断的对象,以此来获取内部Class属性值(只有这一个方法能取到)

Object.prototype.toString() //"[object Object]"

Object.prototype.toString.call([]) === '[object Array]';  //true
Object.prototype.toString.call({}) === '[object Array]';  //false

apply也一样

Object.prototype.toString.apply([]) // "[object Array]"

判断元素是否在数组

array.indexOf() // 返回该元素的下标,未找到返回 -1

['a'].indexOf('a') // 0
['a'].indexOf('b') // -1
'a'.indexOf('a') // 0
'aba'.indexOf('a',1) // 0 第二个参数定义起始搜索位置

添加元素

push

可通过push方法向数组尾部添加多个元素
array.push(element1, element2,...)

var arr = [];
arr.push(1);
console.log(arr) // [1]

可同时添加多个元素,元素间用逗号隔开

arr.push(2,3); 
console.log(arr) // [1, 2, 3]

unshift

可通过push方法向数组头部插入元素
array.unshift(element1, element2,...)

var arr = [1];
arr.unshift(2); 
console.log(arr); // [2, 1]
arr.unshift('a','b');
console.log(arr); // ["a", "b", 2, 1]

push | unshift方法会返回数组长度值

var len = arr.unshift();
console.log(len); // 5

concat

可用concat方法连接多个数组
array.concat()
array.concat(array1,array2,...)

var arr = [1]
var arr2 = arr.concat([2],[3])
console.log(arr2) // [1, 2, 3]

concat方法返回新的数组,不会修改原来的数组对象,因此可用于数组浅复制

var arr = [1];
var arrCopy = arr.concat();
arrCopy.push(2)

//可见原数组arr未发生改变
console.log(arr); // [1]
console.log(arrCopy); // [1, 2]

splice

插入/删除元素.返回一个数组,内含被删除的元素
array.splice(index)
array.splice(index,deleteCount)
array.splice(index,deleteCount,item1,item2,...)

index 插入元素位置,原来在该位置上的元素会自动向后挪
deleteCount 删除元素数个数,小于等于0时不删除元素
itemX 插入元素,可选

var arr = [1 ,2, 3];

arr.splice(0, 0,'a');
console.log(arr); // ["a", 1, 2, 3]

arr.splice(0, 1); // ["a"]
console.log(arr); // [1, 2, 3]

arr.splice(-1, 0, 'a', 'b');
console.log(arr); // [1, 2, "a", "b", 3]

删除元素

pop

array.pop()
删除数组末尾元素

var arr = ['a', 'b'];
arr.pop(); // "b"
arr; // ["a"]

shift

array.shift()
删除数组内第一个元素

var arr = ['a', 'b'];
arr.shift(); // "a"
arr // ["b"]

数组的拷贝(复制)

因为数组对象引用时传递的是内存地址,因此不能像复制字符串一样把数组赋值给其他变量

var arr = [1];
var arrc = arr;
arrc.push(2);
// 修改arrc,arr 也发生改变.因为这两个变量指向的是同一个数组对象.
console.log(arr); //  [1, 2]

浅拷贝

浅拷贝只能复制字符串元素,不能复制数组/对象元素
array.slice()
array.concat()

var arr = [1];
var arrc = arr.slice();
console.log(arrc);

var arrc = arr.concat();
console.log(arrc); //[1]

数组里的数组/对象元素还是指向原来的元素

var arr= [1, [2], {num:3}]
var arrc= arr.slice();
// 修改新数组中的元素
arrc[0] = 'a'
arrc[1][0] = 'b'
arrc[2].num = 'c'
// 原数组中的数组和对象也被修改了
console.log(arr) //  [1, ["b"], {num:"c"}]

arr.push('!');
console.log(arr); // ["a", "b", "c", "!"]
console.log(compareArr); // ["a", "b", "c", "!"]
console.log(arrCopy); // ["a", "b", "c"]

深拷贝

1 JSON.parse(JSON.stringify(array))
用于多维数组拷贝

var arr = [1, [2]]
var arrc =  JSON.parse(JSON.stringify(arr));
arrc[1][0] = 'a';
//原数组没有被改变
console.log(arr[1]); // [2]

console.log(arr[3]); // ["!"]
console.log(compareArr[3]); // ["!"]
console.log(arrDeepCopy[3]); // ["d"]

缺点 不能拷贝函数和Data对象

var arr = [1,2,v => console.log(v)] // [1, 2, function]
JSON.parse(JSON.stringify(arr)); // [1, 2, null]

2 递归深拷贝

function deepCopy(arr) {    
    function _isArr(obj) {
        // 检测是否是数组 , 返回布尔值
        return Object.prototype.toString.call(obj) === '[object Array]';
    }
    var item;
    var arrc = [];
    for (var i = 0; i < arr.length; i++) {
        if (_isArr(arr[i])) {
            //数组
            item = deepCopy(arr[i]);
        } else if (arr[i].constructor === Object) {
            //对象
            item = {};
            for (var key in arr[i]) {
                var value = arr[i][key];
                if (arr[i].hasOwnProperty(key) === true) {
                 item[key] = _isArr(value) ? deepCopy(value) : value;
                }
            }
        } else{
            //其他,例如字符串 Data等
            item = arr[i];
        }
        arrc.push(item);  
      }
    //for end
    return  arrc;
}

var arr = [1,[[2],], {num: [4, function(){console.log('hi')}]}]
var arrc = deepCopy(arr);
arrc[1][0] = 'a';
console.log(arr[1][0]); // [2]

arrc[2].num[0] = 'b';
console.log(arr[2].num[0]); // 4
arr[2].num[1]() //hi

注意 该函数未考虑互相调用的情况

var a = [];
var b = [];
a.push(b);
b.push(a);
deepCopy(a); // Uncaught RangeError: Maximum call stack size exceeded(…)

3 jQuery.extend
利用jQuery拷贝数组
jQuery.extend(true, {}, array) //深拷贝
jQuery.extend(false, {}, array) //浅拷贝

var arr = [1,[[2],], {num: [4, function(){console.log('hi')}]}]
var arrc = jQuery.extend(true, {}, arr)

数组转字符串

toString

array.toString()

var arr = [1 ,2 ,3];
arr.toString(); // "1,2,3"

join

array.join('sep')
sep 元素间的分隔符号,留空时使用逗号分隔

var arr = [1 ,2 ,3];
arr.join(); // "1,2,3"
arr.join(' '); // "1 2 3"

字符串转数组

string.split(sep)
string.split(regExp)
string.split(sep, Maxlength)

var str = "1,2,3"
str.split() // ["1,2,3"]

splite接受正则表达式作为分割依据

var str = "1,,2,,,,3"
str.split(/\,+/) //  ["1", "2", "3"]
str.split(' ', 2) // ["1", "2"]

Maxlength 规定返回数组的最大长度

var str = "1,2,3"
//规定返回数组最大长度为2
 str.split(',',2) // ["1", "2"]

数组的遍历

for

循环语句使用for关键字开头,后接括号.括号内包含三条语句(可选),使用分号(;)分隔
for(initialization; condition; final-expression){statement}

initialization 在循环开始时执行
condition 在单次循环开始前运行.运算结果为true将继续执行,反之结束运行(被省略则一直为true)
final-expression 单次循环结束后运行

var arr = ['a', 'b', 'c'];
for (var i = 0; i < arr.length; i++){
    console.log(i); // 0 1 2
    console.log(arr[i]); // a b c
}

这三条语句均可以被省略

var i = 0;
for(;;){
    console.log(i++); // 0 1 2 3 ...
}

for in

for (var i in array){...}

var arr = ['a', 'b', 'c'];
for(var i in arr){
    console.log(i); // 0 1 2
    console.log(arr[i]); // a b c
}

for in循环中的i看起来像个数字,其实是数组对象的属性名

for(var i in ['a']){
    console.log(i);
    console.log(Object.prototype.toString.call(i) === '[object Number]'); // false
    console.log(Object.prototype.toString.call(i) === '[object String]'); // true      
}

因此,应尽量避免使用for in 遍历数组

var arr = ['a', 'b', 'c'];
//假设某个js库更改了array对象
Array.prototype.name = 'anna';
for(var i in arr){
    //属性name也被遍历出来了
    console.log(i); // 0 1 2 name
    console.log(arr[i]); // a b c anna
}
//而普通的for循环就没有这种问题
for (var i = 0; i < arr.length; i++){
    console.log(i); // 0 1 2
    console.log(arr[i]); // a b c
}

for of

es6的新增方法
for (let i of arr){...}

var arr = ['a', 'b', 'c'];
for(let i of arr){
    console.log(i); // a b c
} 

数组排序

sort

利用sort方法对数组对象排序
arr.sort()
arr.sort(function)

var arr = [2, 1, 3];
arr.sort(); // [1, 2, 3]

可传入一个函数作为排序依据,根据返回值决定是否交换元素位置(返回值是否大于零)

var arr = [2, 1, 3];
arr.sort((x, y) => {return y - x;}); // [3, 2, 1]

//多维数组排序
var arr = [[2, 10],[1, 100],[3, 100]]
arr.sort((x,y) => {
    // 以数组的第一个元素作为排序依据
    return x[0] - y[0];
});
console.log(arr) //[ [1, 100], [2, 10], [3, 100]]

翻转数组

可用reverse方法翻转数组
array.reverse()

var arr = [1, 2, 3];
arr.reverse(); // [3, 2, 1]

注意 sort reverse方法返回的是原来的数组对象,不会返回新的数组

var arr = [2, 1, 3];    
var arrt = arr.sort();
arrt[0] = 'a';
console.log(arr); // ["a", 2, 3]

随机排序

function shuffle(a) {
    var j, x, i;
    for (i = a.length - 1; i > 0; i--) {
        j = Math.floor(Math.random() * (i + 1));
        x = a[i];
        a[i] = a[j];
        a[j] = x;
    }
}
suffle([1, 2, 3, 4, 5]);

How can I shuffle an array? stackoverflow

Math.random()
返回一个[0,1)之间的浮点数(小数)

Math.random() // 0.9480720531476523

// 取[0,100)间的数
Math.random() * 100 // 98.3447739091475

取[min,max)间的整数
Math.floor(Math.random() * (max - min + 1)) + min

// 取[10,100)间的整数 
Math.floor(Math.random() * (100 - 10 + 1)) + 10

// 取[-10, 100]间的整数
Math.floor(Math.random() * (100 + 10 + 1)) - 10

更多详见 stackoverflow