简介

数组是编程语言中应用最广泛的存储结构,在 ECMAScript 中数组是非常常用的引用类型。很有必要将数组的内容捋一遍,加深印象。

数组属性

  • constructor 表示引用数组对象的构造函数
  • length 表示数组的长度,即其中元素的个数。注意在js中length属性是可变的,当设置一个数组的length值变大时,数组内容不会改变,仅仅是length更改,但当length设置小于实际数组的时候,则原数组中索引大于或等于length的元素的值全部被丢失。
  • prototype属性是object共有的,可以通过增加属性和方法扩展数组定义。

基本操作

一、创建方法

创建一个空数组

1
2
var arr = [];
var arr = new Array(); // 创建一个空数组

创建一个指定长度的数组

1
var arr = new Array(size) // size 表示数组的长度

创建一个指定元素的数组

1
var arr = new Array(1,2,3,4,5) //创建数组并赋值 [1,2,3,4,5]

二、检测方法

1、利用 instanceof 操作符

instanceof操作符是检测对象的原型链是否指向构造函数的prototype对象,

1
2
var arr =[1,2,3];
console.log(arr instanceof Array) // true

2、通过对象自身的 constructor 属性

1
2
var arr =[1,2,3];
console.log(arr.constructor === Array) // true

跨frame实例化对象带来的问题

constructorinstanceof 貌似很好的两个检测数组的方法,但实际上还是有些漏洞的,当你在多个frame中回来跳的时候,这两种方法就惨了。

由于每一个frame都有自己的一套执行环境,跨frame实例化的对象彼此并不共享原型链,通过 instanceof 操作符和 constructor 属性检测的方法自然会失败。

那么第三种方法就比较好了,如下

3、对象原生toString检测

Object.prototype.toString 的行为:首先,取得对象的一个内部属性 [[Class]],然后依据这个属性,返回一个类似于”[object Array]“的字符串作为结果(看过ECMA标准的应该都知道,[[]]用来表示语言内部用到的、外部不可直接访问的属性,称为“内部属性”)。利用这 个方法,再配合call,我们可以取得任何对象的内部属性[[Class]],然后把类型检测转化为字符串比较,以达到我们的目的。

1
2
3
var arr =[1,2,3];
console.log(Object.prototype.toString.call(arr) === '[object Array]'); //true

可以将判断方法封装一个函数

1
2
3
4
5
6
function isArray(obj) {
   return Object.prototype.toString.call(obj) === '[object Array]';
}
var arr =[1,2,3];
console.log(isArray(arr)); // true

4、ECMAScript 5的isArray函数

为了让数组检测更方便,ECMAScript5新增了Array.isArray()方法。该方法的目的是最终确定某个值到底是不是数组,而不管它在哪个全局环境中创建的。

注:此方法在IE8之前的版本是不支持的

1
2
3
var arr =[1,2,3];
console.log(Array.isArray(arr)); // true

ECM3方法

1、Array.prototype.join()

join() 方法将数组(或一个类数组对象)的所有元素连接到一个字符串中。此方法不会改变原数组。也就是说所有的数组元素被转换成字符串,再用一个分隔符将这些字符串连接起来。如果元素是undefined 或者null, 则会转化成空字符串。

arr.join(separator) 参数 separator

  • 指定一个字符串来分隔数组的每个元素
  • 如果省略(),数组元素用逗号分隔。默认为 “,”
  • 如果separator是空字符串(""),则所有元素之间都没有任何字符
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var arr = ['a1', 'b2', 'c3'];
var myArr1 = arr.join();
var myArr2 = arr.join(', ');
var myArr3 = arr.join(' + ');
var myArr4 = arr.join('');

console.log(myArr1);  // a1,b2,c3
console.log(myArr2);  // a1, b2, c3
console.log(myArr3);  // a1 + b2 + c3
console.log(myArr4);  // a1b2c3

2、Array.prototype.push()

push() 方法将一个或多个元素添加到数组的末尾,并返回数组的新长度。

**添加元素:**可以添加新的元素到数组

1
2
3
4
5
// 添加元素
var letter = ["a", "b"];
var total = letter.push("c","d");
console.log(total); // 4
console.log(letter); // ["a", "b", "c", "d"]

合并数组:可以使用 apply() 添加第二个数组的所有元素

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 合并数组
var arr1 = [1, 2];
var arr2 = ["a", "b"];

// 将第二个数组融合进第一个数组
// 相当于 arr1.push('a', 'b');
Array.prototype.push.apply(arr1, arr2);

console.log(arr1); // [1, 2, "a", "b"]

3、Array.prototype.pop()

pop()方法从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。

如果你在一个空数组上调用 pop(),它返回 undefined。

4、Array.prototype.unshift()

unshift() 方法将一个或多个元素添加到数组的开头,并返回新数组的长度。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var arr = [1, 2];

arr.unshift(0);
//arr is [0, 1, 2]

arr.unshift(-2, -1); // = 5
//arr is [-2, -1, 0, 1, 2]

arr.unshift( [-3] );
//arr is [[-3], -2, -1, 0, 1, 2]

5、Array.prototype.shift()

shift() 方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
let myFish = ['angel', 'clown', 'mandarin', 'surgeon'];

console.log('调用 shift 之前: ' + myFish);
// "调用 shift 之前: angel,clown,mandarin,surgeon"

var shifted = myFish.shift();

console.log('调用 shift 之后: ' + myFish);
// "调用 shift 之后: clown,mandarin,surgeon"

console.log('被删除的元素: ' + shifted);
// "被删除的元素: angel"

6、Array.prototype.sort()

sort(compareFunction) 方法在适当的位置对数组的元素进行排序,并返回数组。

sort 排序不一定是稳定的。默认排序顺序是根据字符串Unicode码点。

一般我们给sort带入个比较函数来替代原来的默认的比较方法,比较方法接受两个参数:

  • 如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;
  • 如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。
  • 如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前。
  • compareFunction(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。
1
2
3
4
5
var numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
  return a - b;
});
console.log(numbers); // [1, 2, 3, 4, 5]

7、Array.prototype.reverse()

reverse() 方法颠倒数组中元素的位置。第一个元素会成为最后一个,最后一个会成为第一个。

下例将会创建一个数组 myArray,其包含三个元素,然后颠倒该数组。

1
2
3
var myArray = ['a', 'b', 'c'];
myArray.reverse();
console.log(myArray);  // ['c', 'b', 'a']

8、Array.prototype.concat()

concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var arr1 = ["a", "b", "c"];
var arr2 = ["d", "e", "f"];

var arr3 = arr1.concat(arr2);

console.log(arr3);
// 返回结果是一个新数组
// [ "a", "b", "c", "d", "e", "f" ]

// 原数组没有改变
console.log(arr1); // ["a", "b", "c"]
console.log(arr2); // ["d", "e", "f"]

9、Array.prototype.slice()

slice(start, end) 方法将数组的一部分浅拷贝, 返回到从开始到结束(不包括结束)选择的新数组对象。原始数组不会被修改。

  • slice()
  • slice(start)
  • slice(start,end)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
var arr = ['one','two','three','four'];

//如果不传参数,表示从数组0开始到到end(包含end)
var newArr1 = arr.slice();
console.log(newArr1)  // ["one", "two", "three", "four"]

//如果省略 end,则表示从start开始到end(包含end)
var newArr2 = arr.slice(1);
console.log(newArr2) // ["two", "three", "four"]

//如果传人star、end,则表示从start到end不包含end
var newArr3 = arr.slice(1, 3);
console.log(newArr3) // ["two", "three"]

console.log(arr)    // ["one", "two", "three", "four"]

10、Array.prototype.splice()

splice() 方法通过删除现有元素和/或添加新元素来更改数组的内容。

注意:splice 方法直接更改原数组内容

  • array.splice(start)
  • array.splice(start, deleteCount)
  • array.splice(start, deleteCount, item1, item2, …)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var myFish = ["angel", "clown", "mandarin", "surgeon"];

//从第 2 位开始删除 0 个元素,插入 "drum"
var removed = myFish.splice(2, 0, "drum");
console.log(myFish);
//运算后的 myFish:["angel", "clown", "drum", "mandarin", "surgeon"]
//被删除元素数组:[],没有元素被删除

//从第 3 位开始删除 1 个元素
removed = myFish.splice(3, 1);
//运算后的myFish:["angel", "clown", "drum", "surgeon"]
//被删除元素数组:["mandarin"]

//从第 2 位开始删除 1 个元素,然后插入 "trumpet"
removed = myFish.splice(2, 1, "trumpet");
//运算后的myFish: ["angel", "clown", "trumpet", "surgeon"]
//被删除元素数组:["drum"]

//从第 0 位开始删除 2 个元素,然后插入 "parrot", "anemone" 和 "blue"
removed = myFish.splice(0, 2, "parrot", "anemone", "blue");
//运算后的myFish:["parrot", "anemone", "blue", "trumpet", "surgeon"]
//被删除元素的数组:["angel", "clown"]

//从第 3 位开始删除 2 个元素
removed = myFish.splice(3, Number.MAX_VALUE);
//运算后的myFish: ["parrot", "anemone", "blue"]
//被删除元素的数组:["trumpet", "surgeon"]

ECM5方法

1、Array.prototype.indexOf()

indexOf()方法返回在数组中可以找到给定元素的第一个索引,如果不存在,则返回-1。

1
2
3
4
5
6
var a = [2, 6, 9, 6];

a.indexOf(2); // 0
a.indexOf(7); // -1 不存在
a.indexOf(6); // 1 返回指定元素的第一个索引值

找出指定元素出现的所有位置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// 找出 a 在 array 里的所有位置
var str = 'a';
var array = ['a', 'b', 'a', 'c', 'a', 'd'];


var indices = [];
var idx = array.indexOf(str);

while (idx != -1) {
  indices.push(idx);
  idx = array.indexOf(str, idx + 1);
}

console.log(indices);
// [0, 2, 4]

2、Array.prototype.lastIndexOf()

lastIndexOf() 方法返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找,从 fromIndex 处开始。

1
arr.lastIndexOf(searchElement[, fromIndex = arr.length - 1])

定位数组中的值:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var array = [2, 5, 9, 2];
var index = array.lastIndexOf(2);
// index is 3
index = array.lastIndexOf(7);
// index is -1
index = array.lastIndexOf(2, 3);
// index is 3
index = array.lastIndexOf(2, 2);
// index is 0
index = array.lastIndexOf(2, -2);
// index is 0
index = array.lastIndexOf(2, -1);
// index is 3

查找所有元素

下例使用 lastIndexOf 查找到一个元素在数组中所有的索引(下标),并使用 push 将所有添加到另一个数组中。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14

var element = 'a';
var array = ['a', 'b', 'a', 'c', 'a', 'd'];

var indices = [];
var idx = array.lastIndexOf(element);

while (idx != -1) {
  indices.push(idx);
  idx = (idx > 0 ? array.lastIndexOf(element, idx - 1) : -1);
}

console.log(indices);
// [4, 2, 0];

3、Array.prototype.every()

every() 方法测试数组的所有元素是否都通过了指定函数的测试。

every 方法为数组中的每个元素执行一次 callback 函数,直到它找到一个使 callback 返回 false(表示可转换为布尔值 false 的值)的元素。如果发现了一个这样的元素,every 方法将会立即返回 false。否则,callback 为每一个元素返回 true,every 就会返回 true。callback 只会为那些已经被赋值的索引调用。不会为那些被删除或从来没被赋值的索引调用。

callback 被调用时传入三个参数:元素值,元素的索引,原数组。

如果为 every 提供一个 thisArg 参数,在该参数为调用 callback 时的 this 值。如果省略该参数,则 callback 被调用时的 this 值,在非严格模式下为全局对象,在严格模式下传入 undefined。

every 不会改变原数组。

every 遍历的元素范围在第一次调用 callback 之前就已确定了。在调用 every 之后添加到数组中的元素不会被 callback 访问到。如果数组中存在的元素被更改,则他们传入 callback 的值是 every 访问到他们那一刻的值。那些被删除的元素或从来未被赋值的元素将不会被访问到。

检测所有数组元素的大小

1
2
3
4
5
6
7
function isBigEnough(element, index, array) {
  return (element >= 10);
}
var passed = [12, 5, 8, 130, 44].every(isBigEnough);
// passed is false
passed = [12, 54, 18, 130, 44].every(isBigEnough);
// passed is true

4、Array.prototype.some()

some() 方法测试数组中的某些元素是否通过了指定函数的测试。

some 为数组中的每一个元素执行一次 callback 函数,直到找到一个使得 callback 返回一个“真值”(即可转换为布尔值 true 的值)。如果找到了这样一个值,some 将会立即返回 true。否则,some 返回 false。callback 只会在那些”有值“的索引上被调用,不会在那些被删除或从来未被赋值的索引上调用。

callback 被调用时传入三个参数:元素的值,元素的索引,被遍历的数组。

1
arr.some(callback[, thisArg])

如果为 some 提供了一个 thisArg 参数,将会把它传给被调用的 callback,作为 this 值。否则,在非严格模式下将会是全局对象,严格模式下是 undefined。

some 被调用时不会改变数组。

测试数组元素的值

下面的例子检测在数组中是否有元素大于 10。

1
2
3
4
5
6
7
function isBigEnough(element, index, array) {
  return (element >= 10);
}
var passed = [2, 5, 8, 1, 4].some(isBigEnough);
// passed is false
passed = [12, 5, 8, 1, 4].some(isBigEnough);
// passed is true

5、Array.prototype.filter()

filter() 方法使用指定的函数测试所有元素,并创建一个包含所有通过测试的元素的新数组。

对数组中的每一项运行给定函数,返回该函数会返回 true 的项组成的数组。

1
var new_array = arr.filter(callback[, thisArg])

筛选排除掉所有的小值

下例使用 filter 创建了一个新数组,该数组的元素由原数组中值大于 10 的元素组成。

1
2
3
4
5
6
function isBigEnough(value) {
  return value >= 10;
}

var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered is [12, 130, 44]

6、Array.prototype.map()

map() 方法创建一个新数组,其结果是该数组中的每个元素调用一个提供的函数,返回这个新数组

求数组中每个元素的平方根

下面的代码创建了一个新数组,值为原数组中对应数字的平方根。

1
2
3
var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
/* roots的值为[1, 2, 3], numbers的值仍为[1, 4, 9] */

问答题

问题:["1","2","3"].map(parseInt) 答案是多少?

答案是[1,NaN,NaN]

7、Array.prototype.forEach()

forEach() 方法对数组的每个元素执行一次提供的函数。

对数组中的每一项运行给定函数,这个方法没有返回值。本质上与使用 for 循环迭代数组一样。

1
2
3
array.forEach(callback(currentValue, index, array){
    //do something
}, this)
  • currentValue(当前值) 数组中正在处理的当前元素。
  • index(索引) 数组中正在处理的当前元素的索引。
  • array forEach()方法正在操作的数组。
1
2
3
4
5
6
7
8
9
var arr=[2, 4, 5];
arr.forEach(function(elm,index, array) {
   console.log(index, elm);
});

// 0 2
// 1 4
// 2 5

8、Array.prototype.reduce()

reduce() 方法对累加器和数组的每个值 (从左到右)应用一个函数,以将其减少为单个值。

将数组所有项相加

1
2
3
4
var sum = [0, 1, 2, 3].reduce(function(a, b) {
    return a + b;
}, 0);
// sum is 6

数组扁平化

1
2
3
4
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(function(a, b) {
    return a.concat(b);
}, []);
// flattened is [0, 1, 2, 3, 4, 5]

9、Array.prototype.reduceRight()

reduceRight() 方法接受一个函数作为累加器(accumulator),让每个值(从右到左,亦即从尾到头)缩减为一个值。(与 reduce() 的执行方向相反)

1
2
3
4
5
var flattened = [[0, 1], [2, 3], [4, 5]].reduceRight(function(a, b) {
    return a.concat(b);
}, []);

// flattened is [4, 5, 2, 3, 0, 1]

本文主要内容引用:

原文地址: http://zyj1022.github.io/posts/frontend/2017/js-array-base.html

转载时必须以链接形式注明原始出处及本声明