javascript 数组知识点整理

1,453 阅读13分钟

所有的数组实例都继承于 Array.prototype。

Array.prototype 属性的属性特性:
writable(可写) false
enumerable(可枚举) false
configurable(可配置) false

描述

所有的数组方法都定义在 Array.prototype 身上,和其他的构造函数一样,你可以通过扩展 Array 的 prototype 属性上的方法来给所有数组实例增加方法。

还一个鲜为人知的事实:Array.prototype 本身也是个数组。

Array.isArray(Array.prototype); // true

属性

Array.prototype.constructor

所有的数组实例都继承了这个属性,它的值就是 Array,表明了所有的数组都是由 Array 构造出来的。

Array.prototype.constructor.call([1])         // []

Array.prototype.length

上面说了,因为 Array.prototype 也是个数组,所有它也有 length 属性,这个值为 0,因为它是个空数组。

方法

会改变自身的方法

下面的这些方法会改变调用它们的对象自身的值:

1. Array.prototype.copyWithin()

在数组内部,将一段元素序列拷贝到另一段元素序列上,覆盖原有的值。

copyWithin() 方法会浅拷贝数组的部分元素到同一数组的不同位置,且不改变数组的大小,返回该数组。

只有部分浏览器实现,生产中不要使用copyWithin

2. Array.prototype.fill()

将数组中指定区间的所有元素的值,都替换成某个固定的值。

只有部分浏览器实现,生产中不要使用fill

3. Array.prototype.pop()

pop() 方法删除一个数组中的最后的一个元素,并且返回这个元素。

原来的数组会改变。

var myFish = ["angel", "clown", "mandarin", "surgeon"];
myFish.pop();                                 // "surgeon"
myFish;                                       // ["angel", "clown", "mandarin"]
Array.prototype.pop.call(myFish);             // "mandarin"
myFish;                                       // ["angel", "clown"]

4. Array.prototype.push()

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

// 添加元素到数组
var sports = ["soccer", "baseball"];
var total = sports.push("football", "swimming");

console.log(sports); // ["soccer", "baseball", "football", "swimming"]
console.log(total);  // 4
// 合并两个数组
var vegetables = ['parsnip', 'potato'];
var moreVegs = ['celery', 'beetroot'];

Array.prototype.push.apply(vegetables, moreVegs);

console.log(vegetables); // ['parsnip', 'potato', 'celery', 'beetroot']

上面的例子中如果是call,则结果是["parsnip", "potato", Array[2]]

像数组一样使用对象

如上所述,push 是特意设计为通用的,我们可以使用它来获得便利。正如下面的例子所示,Array.prototype.push 可以在一个对象上工作。 注意,我们没有创建一个数组来存储对象的集合。 相反,我们将该集合存储在对象本身上,并使用在 Array.prototype.push 上使用的 call 来调用该方法,使其认为我们正在处理数组,而它只是像平常一样运作,这要感谢 JavaScript 允许我们建立任意的执行上下文。

var obj = {
    length: 0,

    addElem: function addElem (elem) {
        // obj.length is automatically incremented
        // every time an element is added.
        [].push.call(this, elem);
    }
};

// Let's add some empty objects just to illustrate.
obj.addElem({});
obj.addElem({});
console.log(obj.length);
// → 2

注意,尽管 obj 不是数组,但是 push 方法成功地使 obj 的 length 属性增长了,就像我们处理一个实际的数组一样。

5. Array.prototype.reverse()

颠倒数组中元素的排列顺序,即原先的第一个变为最后一个,原先的最后一个变为第一个。

var myArray = ['one', 'two', 'three'];
myArray.reverse();                           // ["three", "two", "one"]

[].reverse.call(myArray);                    // ['one', 'two', 'three']

6. Array.prototype.shift()

删除数组的第一个元素,并返回这个元素。原来的数组会发生变化。

var myFish = ['angel', 'clown', 'mandarin', 'surgeon'];
[].shift.call(myFish);                                     // "angel"

7. Array.prototype.unshift()

unshift() 方法在数组的开头添加一个或者多个元素,并返回数组新的 length 值。

var arr = [1, 2];

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

8. Array.prototype.sort()

sort() 方法在适当的位置对数组的元素进行排序,并返回数组。 sort 排序不一定是稳定的。默认排序顺序是根据字符串Unicode码点。

var scores = [1, 10, 2, 21];
scores.sort();              // [1, 10, 2, 21]
var numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
  return a - b;
});
console.log(numbers);              // [1, 2, 3, 4, 5]

更多用法见sort

9. Array.prototype.splice()

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

参数一start:指定修改的开始位置(从0计数)。如果超出了数组的长度,则从数组末尾开始添加内容;如果是负值,则表示从数组末位开始的第几位。

参数二deleteCount(可选):整数,表示要移除的数组元素的个数。如果 deleteCount 是 0,则不移除元素。这种情况下,至少应添加一个新元素。如果 deleteCount 大于start 之后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。如果deleteCount被省略,则其相当于(arr.length - start)。

参数三item1, item2, ... (可选):要添加进数组的元素,从start 位置开始。如果不指定,则 splice() 将只删除数组元素。

返回值:由被删除的元素组成的一个数组。如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。

var myFish = ["angel", "clown", "mandarin", "sturgeon"];

myFish.splice(2, 0, "drum");
// myFish is ["angel", "clown", "drum", "mandarin", "sturgeon"]

myFish.splice(2, 1);
// myFish is ["angel", "clown", "mandarin", "sturgeon"]

myFish.splice(2, 1, "splice", "parrot");
// myFish is ["angel", "clown", "splice", "parrot", "sturgeon"]

不会改变自身的方法

下面的这些方法绝对不会改变调用它们的对象的值,只会返回一个新的数组或者返回一个其它的期望值。

10. Array.prototype.concat()

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

var arr1 = ["a", "b", "c"];
var arr2 = ["d", "e", "f"];

var arr3 = arr1.concat(arr2);        // [ "a", "b", "c", "d", "e", "f" ]

var arr4 = arr1.concat(1,2,arr2);    // [ "a", "b", "c", 1, 2, "d", "e", "f" ]

11. Array.prototype.includes()

includes() 方法用来判断当前数组是否包含某指定的值,如果是,则返回 true,否则返回 false。

参数一searchElement:需要查找的元素值。

参数二fromIndex:可选参数。从该索引处开始查找 searchElement,默认为 0。

[1, 2, 3].includes(2);     // true
[1, 2, 3].includes(4);     // false
[1, 2, 3].includes(3, 3);  // false
[1, 2, 3].includes(3, -1); // true
[1, 2, NaN].includes(NaN); // true

只有部分浏览器实现,生产中不要使用includes

12. Array.prototype.join()

join() 方法将数组(或一个类数组对象)的所有元素连接到一个字符串中。

var a = ['Wind', 'Rain', 'Fire'];
a.join();                  // 'Wind,Rain,Fire'
a.join('-');               // 'Wind-Rain-Fire'

13. Array.prototype.slice()

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

var a = ["zero", "one", "two", "three"];
var sliced = a.slice(1,3);

console.log(a);                      // ["zero", "one", "two", "three"]
cosole.log(sliced);                  // ["one", "two"]

slice(-2,-1)表示抽取了原数组中的倒数第二个元素到最后一个元素(不包含最后一个元素,也就是说只有倒数第二个元素)

slice 方法可以用来将一个类数组(Array-like)对象/集合转换成一个数组。你只需将该方法绑定到这个对象上。下述代码中 list 函数中的 arguments 就是一个类数组对象。

function list() {
  return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

除了使用 Array.prototype.slice.call(arguments),你也可以简单的使用 [].slice.call(arguments) 来代替。另外,你可以使用 bind 来简化该过程。

var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);

function list() {
  return slice(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

14. Array.prototype.toSource()

返回一个表示当前数组字面量的字符串。遮蔽了原型链上的 Object.prototype.toSource() 方法。

⚠️该特性是非标准的,请尽量不要在生产环境中使用它!toSource

15. Array.prototype.toString()

返回一个由所有数组元素组合而成的字符串。遮蔽了原型链上的 Object.prototype.toString() 方法。

var monthNames = ['Jan', 'Feb', 'Mar', 'Apr'];
var myVar = monthNames.toString();               // "Jan,Feb,Mar,Apr"

16. Array.prototype.toLocaleString()

返回一个由所有数组元素组合而成的本地化后的字符串。遮蔽了原型链上的 Object.prototype.toLocaleString() 方法。

数组中的元素将使用各自的 toLocaleString 方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 ",")隔开。

var number = 1337;
var date = new Date();
var myArr = [number, date, "foo"];

var str = myArr.toLocaleString();

console.log(str);
// 输出 "1337,2015/2/27 下午8:29:04,foo"
// 假定运行在中文(zh-CN)环境,北京时区

17. Array.prototype.indexOf()

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

var array = [2, 5, 9];
array.indexOf(2);     // 0
array.indexOf(7);     // -1
array.indexOf(9, 2);  // 2
array.indexOf(2, -1); // -1
array.indexOf(2, -3); // 0

18. Array.prototype.lastIndexOf()

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

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

遍历方法

在下面的众多遍历方法中,有很多方法都需要指定一个回调函数作为参数。在回调函数执行之前,数组的长度会被缓存在某个地方,所以,如果你在回调函数中为当前数组添加了新的元素,那么那些新添加的元素是不会被遍历到的。此外,如果在回调函数中对当前数组进行了其它修改,比如改变某个元素的值或者删掉某个元素,那么随后的遍历操作可能会受到未预期的影响。总之,不要尝试在遍历过程中对原数组进行任何修改,虽然规范对这样的操作进行了详细的定义,但为了可读性和可维护性,请不要这样做。

19. Array.prototype.forEach()

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

thisArg 可选参数。当执行回调 函数时用作this的值(参考对象)。

forEach 方法按升序为数组中含有效值的每一项执行一次callback 函数,那些已删除(使用delete方法等情况)或者未初始化的项将被跳过(但不包括那些值为 undefined 的项)(例如在稀疏数组上)。

callback 函数会被依次传入三个参数:

  • 数组当前项的值
  • 数组当前项的索引
  • 数组对象本身

如果给forEach传递了thisArg参数,当调用时,它将被传给callback 函数,作为它的this值。否则,将会传入 undefined 作为它的this值。callback函数最终可观察到this值,这取决于 函数观察到this的常用规则。

forEach 遍历的范围在第一次调用 callback 前就会确定。调用forEach 后添加到数组中的项不会被 callback 访问到。如果已经存在的值被改变,则传递给 callback 的值是 forEach 遍历到他们那一刻的值。已删除的项不会被遍历到。如果已访问的元素在迭代时被删除了(例如使用 shift()) ,之后的元素将被跳过 - 参见下面的示例。

forEach() 为每个数组元素执行callback函数;不像map() 或者reduce() ,它总是返回 undefined值,并且不可链式调用。典型用例是在一个链的最后执行副作用。

function logArrayElements(element, index, array) {
    console.log("a[" + index + "] = " + element);
}

// 注意索引2被跳过了,因为在数组的这个位置没有项
[2, 5, ,9].forEach(logArrayElements);
// logs:
// a[0] = 2
// a[1] = 5
// a[3] = 9
function Counter() {
  this.sum = 0;
  this.count = 0;
}
Counter.prototype.add = function(array) {
  array.forEach(function(entry) {
    this.sum += entry;
    ++this.count;
  }, this);
  // ^---- 注意
};

var obj = new Counter();
obj.add([2, 5, 9]);
obj.count
// 3
obj.sum
// 16

20. Array.prototype.every()

如果数组中的每个元素都满足测试函数,则返回 true,否则返回 false。

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

更多

21. Array.prototype.some()

如果数组中至少有一个元素满足测试函数,则返回 true,否则返回 false。

和every类似。

更多

22. Array.prototype.filter()

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

function isBigEnough(element) {
  return element >= 10;
}
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered is [12, 130, 44]

更多

23. Array.prototype.map()

map() 方法返回一个由原数组中的每个元素调用一个指定方法后的返回值组成的新数组。

var map = Array.prototype.map
var a = map.call("Hello World", function(x) {
  return x.charCodeAt(0);
})

更多

24. Array.prototype.reduce()

从左到右为每个数组元素执行一次回调函数,并把上次回调函数的返回值放在一个暂存器中传给下次回调函数,并返回最后一次回调函数的返回值。

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

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

更多

25. Array.prototype.reduceRight()

从右到左为每个数组元素执行一次回调函数,并把上次回调函数的返回值放在一个暂存器中传给下次回调函数,并返回最后一次回调函数的返回值。

var total = [0, 1, 2, 3].reduceRight(function(a, b) {
    return a + b;
});
// total == 6

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

更多

26. Array.prototype.find()

找到第一个满足测试函数的元素并返回那个元素的值,如果找不到,则返回 undefined。

function isBigEnough(element) {
  return element >= 15;
}

[12, 5, 8, 130, 44].find(isBigEnough); // 130

只有部分浏览器实现,生产中不要使用find

27. Array.prototype.findIndex()

findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。

function isBigEnough(element) {
  return element >= 15;
}

[12, 5, 8, 130, 44].findIndex(isBigEnough); // 3

只有部分浏览器实现,生产中不要使用findIndex

28. Array.prototype.entries()

返回一个数组迭代器对象,该迭代器会包含所有数组元素的键值对。

var arr = ["a", "b", "c"];
var eArr = arr.entries();

console.log(eArr.next().value); // [0, "a"]
console.log(eArr.next().value); // [1, "b"]
console.log(eArr.next().value); // [2, "c"]

只有部分浏览器实现,生产中不要使用entries

29. Array.prototype.keys()

返回一个数组迭代器对象,该迭代器会包含所有数组元素的键。

var arr = ["a", "b", "c"];
var iterator = arr.keys();

console.log(iterator.next()); // { value: 0, done: false }
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: undefined, done: true }

只有部分浏览器实现,生产中不要使用keys

30. Array.prototype.values()

返回一个数组迭代器对象,该迭代器会包含所有数组元素的值。

var arr = ['w', 'y', 'k', 'o', 'p'];
var eArr = arr.values();
// 您的浏览器必须支持 for..of 循环
// 以及 let —— 将变量作用域限定在 for 循环中
for (let letter of eArr) {
  console.log(letter);
}
var arr = ['w', 'y', 'k', 'o', 'p'];
var eArr = arr.values();
console.log(eArr.next().value); // w
console.log(eArr.next().value); // y
console.log(eArr.next().value); // k
console.log(eArr.next().value); // o
console.log(eArr.next().value); // p

只有部分浏览器实现,生产中不要使用values

31. Array.prototype[@@iterator]()

@@iterator属性和 values() 属性的初始值均为同一个函数对象

var arr = ['w', 'y', 'k', 'o', 'p'];
// 您的浏览器必须支持for...of循环
// 以及let —— 将变量作用域限定在 for 循环中
for (let letter of arr) {
  console.log(letter);
}
var arr = ['w', 'y', 'k', 'o', 'p'];
var eArr = arr[Symbol.iterator]();
console.log(eArr.next().value); // w
console.log(eArr.next().value); // y
console.log(eArr.next().value); // k
console.log(eArr.next().value); // o
console.log(eArr.next().value); // p

只有部分浏览器实现,生产中不要使用@@iterator

参考资料:MDN