https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array

JavaScript的 Array 对象是用于构造数组的全局对象,数组是类似于列表的高阶对象。

常用操作

创建数组

  1. var fruits = ['Apple', 'Banana'];
  2. console.log(fruits.length);
  3. // 2

通过索引访问数组元素

  1. var first = fruits[0];
  2. // Apple
  3. var last = fruits[fruits.length - 1];
  4. // Banana

遍历数组

  1. fruits.forEach(function (item, index, array) {
  2. console.log(item, index);
  3. });
  4. // Apple 0
  5. // Banana 1

添加元素到数组的末尾

  1. var newLength = fruits.push('Orange');
  2. // newLength:3; fruits: ["Apple", "Banana", "Orange"]

删除数组末尾的元素

  1. var last = fruits.pop(); // remove Orange (from the end)
  2. // last: "Orange"; fruits: ["Apple", "Banana"];

删除数组最前面(头部)的元素

  1. var first = fruits.shift(); // remove Apple from the front
  2. // first: "Apple"; fruits: ["Banana"];

添加元素到数组的头部

  1. var newLength = fruits.unshift('Strawberry') // add to the front
  2. // ["Strawberry", "Banana"];

找出某个元素在数组中的索引

  1. fruits.push('Mango');
  2. // ["Strawberry", "Banana", "Mango"]
  3. var pos = fruits.indexOf('Banana');
  4. // 1

通过索引删除某个元素

  1. var removedItem = fruits.splice(pos, 1); // this is how to remove an item
  2. // ["Strawberry", "Mango"]

从一个索引位置删除多个元素

  1. var vegetables = ['Cabbage', 'Turnip', 'Radish', 'Carrot'];
  2. console.log(vegetables);
  3. // ["Cabbage", "Turnip", "Radish", "Carrot"]
  4. var pos = 1, n = 2;
  5. var removedItems = vegetables.splice(pos, n);
  6. // this is how to remove items, n defines the number of items to be removed,
  7. // from that position(pos) onward to the end of array.
  8. console.log(vegetables);
  9. // ["Cabbage", "Carrot"] (the original array is changed)
  10. console.log(removedItems);
  11. // ["Turnip", "Radish"]

复制一个数组

  1. var shallowCopy = fruits.slice(); // this is how to make a copy
  2. // ["Strawberry", "Mango"]

语法

  1. [element0, element1, ..., elementN]
  2. new Array(element0, element1[, ...[, elementN]])
  3. new Array(arrayLength)

参数

elementN

Array 构造器会根据给定的元素创建一个 JavaScript 数组,但是当仅有一个参数且为数字时除外(详见下面的 arrayLength 参数)。注意,后面这种情况仅适用于用 Array 构造器创建数组,而不适用于用方括号创建的数组字面量。

arrayLength

一个范围在 0 到 232-1 之间的整数,此时将返回一个 length 的值等于 arrayLength 的数组对象(言外之意就是该数组此时并没有包含任何实际的元素,不能理所当然地认为它包含 arrayLength 个值为 undefined 的元素)。如果传入的参数不是有效值,则会抛出 RangeError 异常。

描述

数组是一种类列表对象,它的原型中提供了遍历和修改元素的相关操作。JavaScript 数组的长度和元素类型都是非固定的。因为数组的长度可随时改变,并且其数据在内存中也可以不连续,所以 JavaScript 数组不一定是密集型的,这取决于它的使用方式。一般来说,数组的这些特性会给使用带来方便,但如果这些特性不适用于你的特定使用场景的话,可以考虑使用类型数组 TypedArray

只能用整数作为数组元素的索引,而不能用字符串。后者称为关联数组。使用非整数并通过方括号点号来访问或设置数组元素时,所操作的并不是数组列表中的元素,而是数组对象的属性集合上的变量。数组对象的属性和数组元素列表是分开存储的,并且数组的遍历和修改操作也不能作用于这些命名属性。

访问数组元素

JavaScript 数组的索引是从0开始的,第一个元素的索引为0,最后一个元素的索引等于该数组的长度减1。如果指定的索引是一个无效值,JavaScript 数组并不会报错,而是会返回 undefined。

  1. var arr = ['this is the first element', 'this is the second element', 'this is the last element'];
  2. console.log(arr[0]); // 打印 'this is the first element'
  3. console.log(arr[1]); // 打印 'this is the second element'
  4. console.log(arr[arr.length - 1]); // 打印 'this is the last element'

虽然数组元素可以看做是数组对象的属性,就像 toString 一样,但是下面的写法是错误的,运行时会抛出 SyntaxError 异常,而原因则是使用了非法的属性名:

  1. console.log(arr.0); // a syntax error

并不是 JavaScript 数组有什么特殊之处,而是因为在 JavaScript 中,以数字开头的属性不能用点号引用,必须用方括号。比如,如果一个对象有一个名为 3d 的属性,那么只能用方括号来引用它。下面是具体的例子:

  1. var years = [1950, 1960, 1970, 1980, 1990, 2000, 2010];
  2. console.log(years.0); // 语法错误
  3. console.log(years[0]); // √
  1. renderer.3d.setTexture(model, 'character.png'); // 语法错误
  2. renderer['3d'].setTexture(model, 'character.png'); // √

注意在 3d 那个例子中,引号是必须的。你也可以将数组的索引用引号引起来,比如 years[2] 可以写成 years[‘2’]。 years[2] 中的 2 会被 JavaScript 解释器通过调用 toString 隐式转换成字符串。正因为这样,’2’ 和 ‘02’ 在 years 中所引用的可能是不同位置上的元素。而下面这个例子也可能会打印 true:

  1. console.log(years['2'] != years['02']);

类似地,如果对象的属性名称是保留字(最好不要这么做!),那么就只能通过字符串的形式用方括号来访问(从 firefox 40.0a2 开始也支持用点号访问了):

  1. var promise = {
  2. 'var' : 'text',
  3. 'array': [1, 2, 3, 4]
  4. };
  5. console.log(promise['var']);

length 和数字下标之间的关系

JavaScript 数组的 length 属性和其数字下标之间有着紧密的联系。数组内置的几个方法(例如 joinsliceindexOf 等)都会考虑 length 的值。另外还有一些方法(例如 pushsplice 等)还会改变 length 的值。

  1. var fruits = [];
  2. fruits.push('banana', 'apple', 'peach');
  3. console.log(fruits.length); // 3

使用一个合法的下标为数组元素赋值,并且该下标超出了当前数组的大小的时候,解释器会同时修改 length 的值:

  1. fruits[5] = 'mango';
  2. console.log(fruits[5]); // 'mango'
  3. console.log(Object.keys(fruits)); // ['0', '1', '2', '5']
  4. console.log(fruits.length); // 6

也可以显式地给 length 赋一个更大的值:

  1. fruits.length = 10;
  2. console.log(Object.keys(fruits)); // ['0', '1', '2', '5']
  3. console.log(fruits.length); // 10

而为 length 赋一个更小的值则会删掉一部分元素:

  1. fruits.length = 2;
  2. console.log(Object.keys(fruits)); // ['0', '1']
  3. console.log(fruits.length); // 2

这一节的内容在 Array.length 中有更详细的介绍。

正则匹配结果所返回的数组

使用正则表达式匹配字符串可以得到一个数组。这个数组中包含本次匹配的相关信息和匹配结果。RegExp.execString.matchString.replace 都会返回这样的数组。看下面的例子和例子下面的表格:

  1. // 匹配1个 d 后面紧跟着至少1个 b,再后面又跟着1个 d 的子串,
  2. // 并且需要记住子串中匹配到的 b 和最后的 d (通过正则表达式中的分组),
  3. // 同时在匹配时忽略大小写
  4. myRe = /d(b+)(d)/i;
  5. myArray = myRe.exec("cdbBdbsbz");

该正则匹配返回的数组包含以下属性和元素:

属性/元素 说明 示例
input 只读属性,原始字符串 cdbBdbsbz
index 只读属性,匹配到的子串在原始字符串中的索引 1
[0] 只读元素,本次匹配到的子串 dbBd
[1], …[n] 只读元素,正则表达式中所指定的分组所匹配到的子串,其数量由正则中的分组数量决定,无最大上限 [1]: bB[2]: d

属性

Array.length

Array 构造函数的 length 属性,其值为1(注意该属性为静态属性,不是数组实例的 length 属性)。

length 是Array的实例属性。返回或设置一个数组中的元素个数。该值是一个无符号 32-bit 整数,并且总是大于数组最高项的下标。

  1. const clothing = ['shoes', 'shirts', 'socks', 'sweaters'];
  2. console.log(clothing.length);
  3. // expected output: 4

描述

length 属性的值是一个 0 到 232-1 的整数。

  1. var namelistA = new Array(4294967296); // 2的32次方 = 4294967296
  2. var namelistC = new Array(-100) // 负号
  3. console.log(namelistA.length); // RangeError: 无效数组长度
  4. console.log(namelistC.length); // RangeError: 无效数组长度
  5. var namelistB = [];
  6. namelistB.length = Math.pow(2,32)-1; //set array length less than 2 to the 32nd power
  7. console.log(namelistB.length);
  8. // 4294967295

你可以设置 length 属性的值来截断任何数组。当通过改变length属性值来扩展数组时,实际元素的数目将会增加。例如:将一个拥有 2 个元素的数组的 length 属性值设为 3 时,那么这个数组将会包含3个元素,并且,第三个元素的值将会是 undefined 。

  1. var arr = [1, 2, 3];
  2. printEntries(arr);
  3. arr.length = 5; // set array length to 5 while currently 3.
  4. printEntries(arr);
  5. function printEntries(arr) {
  6. var goNext = true;
  7. var entries = arr.entries();
  8. while (goNext) {
  9. var result = entries.next();
  10. if (result.done !== true) {
  11. console.log(result.value[1]);
  12. goNext = true;
  13. } else
  14. goNext = false;
  15. }
  16. console.log('=== printed ===');
  17. }
  18. // 1
  19. // 2
  20. // 3
  21. // === printed ===
  22. // 1
  23. // 2
  24. // 3
  25. // undefined
  26. // undefined
  27. // === printed ===
Array.length 属性的属性特性:
writable true
enumerable false
configurable false
  • Writable :如果设置为false,该属性值将不能被修改。
  • Configurable :如果设置为false,删除或更改任何属性都将会失败。
  • Enumerable :如果设置为 true ,属性可以通过迭代器forfor…in进行迭代。

示例

遍历数组

下面的例子中,通过数组下标遍历数组元素,并把每个元素的值修改为原值的2倍。

  1. var numbers = [1, 2, 3, 4, 5];
  2. var length = numbers.length;
  3. for (var i = 0; i < length; i++) {
  4. numbers[i] *= 2;
  5. }
  6. // 遍历后的结果 [2, 4, 6, 8, 10]

截断数组
下面的例子中,如果数组长度大于 3,则把该数组的长度截断为 3 。

  1. var numbers = [1, 2, 3, 4, 5];
  2. if (numbers.length > 3) {
  3. numbers.length = 3;
  4. }
  5. console.log(numbers); // [1, 2, 3]
  6. console.log(numbers.length); // 3

get Array[@@species]

返回 Array 构造函数。

语法

  1. Array[Symbol.species]

描述

species 访问器属性返回 Array 对象的默认构造函数。子类的构造函数可能会覆盖并改变构造函数的赋值。

  1. Array[Symbol.species]; // function Array()

在继承类的对象中(例如你自定义的数组 MyArray),MyArray 的 species 属性返回的是 MyArray 这个构造函数. 然而你可能想要覆盖它,以便在你继承的对象 MyArray 中返回父类的构造函数 Array :

  1. class MyArray extends Array {
  2. // 重写 MyArray 的 species 属性到父类 Array 的构造函数
  3. static get [Symbol.species]() { return Array; }
  4. }

Array.prototype

通过数组的原型对象可以为所有数组对象添加属性。

Array.prototype 属性表示 Array 构造函数的原型,并允许您向所有Array对象添加新的属性和方法。

  1. /*
  2. 如果JavaScript本身不提供 first() 方法,
  3. 添加一个返回数组的第一个元素的新方法。
  4. */
  5. if(!Array.prototype.first) {
  6. Array.prototype.first = function() {
  7. console.log(`如果JavaScript本身不提供 first() 方法,
  8. 添加一个返回数组的第一个元素的新方法。`);
  9. return this[0];
  10. }
  11. }

Array.prototype[@@unscopables]

Symbol 属性 @@unscopable 包含了所有 ES2015 (ES6) 中新定义的、且并未被更早的 ECMAScript 标准收纳的属性名。这些属性被排除在由 with 语句绑定的环境中。

语法

  1. Array.prototype[@@unscopables]

描述

with 绑定中未包含的数组默认属性有:

参考 Symbol.unscopables 以了解如何为自定义的对象设置 unscopables。

Array.prototype[@@unscopables] 属性的属性特性:
writable false
enumerable false
configurable true

示例

以下的代码在 ES5 或更早的版本中能正常工作。然而 ECMAScript 2015 (ES6) 或之后的版本中新添加了 Array.prototype.keys() 这个方法。这意味着在 with 语句的作用域中,”keys”只能作为方法,而不能作为某个变量。这正是内置的 @@unscopables 即 Array.prototype[@@unscopables] symbol 属性所要解决的问题:防止某些数组方法被添加到 with 语句的作用域内。

  1. var keys = [];
  2. with(Array.prototype) {
  3. keys.push("something");
  4. }
  5. Object.keys(Array.prototype[Symbol.unscopables]);
  6. // ["copyWithin", "entries", "fill", "find", "findIndex",
  7. // "includes", "keys", "values"]

方法

Array.from()

从类数组对象或者可迭代对象中创建一个新的数组实例。

Array.from() 方法从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。

  1. console.log(Array.from('foo'));
  2. // expected output: Array ["f", "o", "o"]
  3. console.log(Array.from([1, 2, 3], x => x + x));
  4. // expected output: Array [2, 4, 6]

语法

  1. Array.from(arrayLike[, mapFn[, thisArg]])

参数

arrayLike

想要转换成数组的伪数组对象或可迭代对象。

mapFn | 可选

如果指定了该参数,新数组中的每个元素会执行该回调函数。

thisArg | 可选

可选参数,执行回调函数 mapFn 时 this 对象。

返回值

一个新的数组实例。

描述

Array.from() 可以通过以下方式来创建数组对象:

  • 伪数组对象(拥有一个 length 属性和若干索引属性的任意对象)
  • 可迭代对象(可以获取对象中的元素,如 Map和 Set 等)

Array.from() 方法有一个可选参数 mapFn,让你可以在最后生成的数组上再执行一次 map 方法后再返回。也就是说 Array.from(obj, mapFn, thisArg) 就相当于 Array.from(obj).map(mapFn, thisArg), 除非创建的不是可用的中间数组。 这对一些数组的子类,如 typed arrays 来说很重要, 因为中间数组的值在调用 map() 时需要是适当的类型。

from() 的 length 属性为 1 ,即 Array.from.length === 1。

在 ES2015 中, Class 语法允许我们为内置类型(比如 Array)和自定义类新建子类(比如叫 SubArray)。这些子类也会继承父类的静态方法,比如 SubArray.from(),调用该方法后会返回子类 SubArray 的一个实例,而不是 Array 的实例。

示例

从 String 生成数组

  1. Array.from('foo');
  2. // [ "f", "o", "o" ]

从 Set 生成数组

  1. const set = new Set(['foo', 'bar', 'baz', 'foo']);
  2. Array.from(set);
  3. // [ "foo", "bar", "baz" ]

从 Map 生成数组

  1. const map = new Map([[1, 2], [2, 4], [4, 8]]);
  2. Array.from(map);
  3. // [[1, 2], [2, 4], [4, 8]]
  4. const mapper = new Map([['1', 'a'], ['2', 'b']]);
  5. Array.from(mapper.values());
  6. // ['a', 'b'];
  7. Array.from(mapper.keys());
  8. // ['1', '2'];

从类数组对象(arguments)生成数组

  1. function f() {
  2. return Array.from(arguments);
  3. }
  4. f(1, 2, 3);
  5. // [ 1, 2, 3 ]

在 Array.from 中使用箭头函数

  1. // Using an arrow function as the map function to
  2. // manipulate the elements
  3. Array.from([1, 2, 3], x => x + x);
  4. // [2, 4, 6]
  5. // Generate a sequence of numbers
  6. // Since the array is initialized with `undefined` on each position,
  7. // the value of `v` below will be `undefined`
  8. Array.from({length: 5}, (v, i) => i);
  9. // [0, 1, 2, 3, 4]

Sequence generator (range)序列发生器(范围)

  1. // Sequence generator function (commonly referred to as "range", e.g. Clojure, PHP etc)
  2. const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));
  3. // Generate numbers range 0..4
  4. range(0, 4, 1);
  5. // [0, 1, 2, 3, 4]
  6. // Generate numbers range 1..10 with step of 2
  7. range(1, 10, 2);
  8. // [1, 3, 5, 7, 9]
  9. // Generate the alphabet using Array.from making use of it being ordered as a sequence
  10. range('A'.charCodeAt(0), 'Z'.charCodeAt(0), 1).map(x => String.fromCharCode(x));
  11. // ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]

数组去重合并

  1. function combine(){
  2. let arr = [].concat.apply([], arguments); //没有去重复的新数组
  3. return Array.from(new Set(arr));
  4. }
  5. var m = [1, 2, 2], n = [2,3,3];
  6. console.log(combine(m,n)); // [1, 2, 3]

Polyfill

ECMA-262 第六版标准中添加了 Array.from 。有些实现中可能尚未包括在其中。你可以通过在脚本前添加如下内容作为替代方法,以使用未原生支持的 Array.from 方法。该算法按照 ECMA-262 第六版中的规范实现,并假定 Object 和 TypeError 有其本身的值, callback.call 对应 Function.prototype.call 。此外,鉴于无法使用 Polyfill 实现真正的的迭代器,该实现不支持规范中定义的泛型可迭代元素。

  1. // Production steps of ECMA-262, Edition 6, 22.1.2.1
  2. if (!Array.from) {
  3. Array.from = (function () {
  4. var toStr = Object.prototype.toString;
  5. var isCallable = function (fn) {
  6. return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
  7. };
  8. var toInteger = function (value) {
  9. var number = Number(value);
  10. if (isNaN(number)) { return 0; }
  11. if (number === 0 || !isFinite(number)) { return number; }
  12. return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
  13. };
  14. var maxSafeInteger = Math.pow(2, 53) - 1;
  15. var toLength = function (value) {
  16. var len = toInteger(value);
  17. return Math.min(Math.max(len, 0), maxSafeInteger);
  18. };
  19. // The length property of the from method is 1.
  20. return function from(arrayLike/*, mapFn, thisArg */) {
  21. // 1. Let C be the this value.
  22. var C = this;
  23. // 2. Let items be ToObject(arrayLike).
  24. var items = Object(arrayLike);
  25. // 3. ReturnIfAbrupt(items).
  26. if (arrayLike == null) {
  27. throw new TypeError("Array.from requires an array-like object - not null or undefined");
  28. }
  29. // 4. If mapfn is undefined, then let mapping be false.
  30. var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
  31. var T;
  32. if (typeof mapFn !== 'undefined') {
  33. // 5. else
  34. // 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
  35. if (!isCallable(mapFn)) {
  36. throw new TypeError('Array.from: when provided, the second argument must be a function');
  37. }
  38. // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
  39. if (arguments.length > 2) {
  40. T = arguments[2];
  41. }
  42. }
  43. // 10. Let lenValue be Get(items, "length").
  44. // 11. Let len be ToLength(lenValue).
  45. var len = toLength(items.length);
  46. // 13. If IsConstructor(C) is true, then
  47. // 13. a. Let A be the result of calling the [[Construct]] internal method
  48. // of C with an argument list containing the single item len.
  49. // 14. a. Else, Let A be ArrayCreate(len).
  50. var A = isCallable(C) ? Object(new C(len)) : new Array(len);
  51. // 16. Let k be 0.
  52. var k = 0;
  53. // 17. Repeat, while k < len… (also steps a - h)
  54. var kValue;
  55. while (k < len) {
  56. kValue = items[k];
  57. if (mapFn) {
  58. A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
  59. } else {
  60. A[k] = kValue;
  61. }
  62. k += 1;
  63. }
  64. // 18. Let putStatus be Put(A, "length", len, true).
  65. A.length = len;
  66. // 20. Return A.
  67. return A;
  68. };
  69. }());
  70. }

Array.isArray()

用来判断某个变量是否是一个数组对象。

Array.isArray() 用于确定传递的值是否是一个 Array

  1. Array.isArray([1, 2, 3]);
  2. // true
  3. Array.isArray({foo: 123});
  4. // false
  5. Array.isArray("foobar");
  6. // false
  7. Array.isArray(undefined);
  8. // false

语法

  1. Array.isArray(obj)

参数

obj

需要检测的值。

返回值

如果值是 Array,则为true; 否则为false。

描述

如果对象是 Array ,则返回true,否则为false。

有关更多详细信息,请参阅文章严格判定JavaScript对象是否为数组

See the article “Determining with absolute accuracy whether or not a JavaScript object is an array” for more details. Given a TypedArray instance, false is always returned.

示例

  1. // 下面的函数调用都返回 true
  2. Array.isArray([]);
  3. Array.isArray([1]);
  4. Array.isArray(new Array());
  5. Array.isArray(new Array('a', 'b', 'c', 'd'))
  6. // 鲜为人知的事实:其实 Array.prototype 也是一个数组。
  7. Array.isArray(Array.prototype);
  8. // 下面的函数调用都返回 false
  9. Array.isArray();
  10. Array.isArray({});
  11. Array.isArray(null);
  12. Array.isArray(undefined);
  13. Array.isArray(17);
  14. Array.isArray('Array');
  15. Array.isArray(true);
  16. Array.isArray(false);
  17. Array.isArray(new Uint8Array(32))
  18. Array.isArray({ __proto__: Array.prototype });

instanceof 和 isArray

当检测Array实例时, Array.isArray 优于 instanceof,因为Array.isArray能检测iframes.

  1. var iframe = document.createElement('iframe');
  2. document.body.appendChild(iframe);
  3. xArray = window.frames[window.frames.length-1].Array;
  4. var arr = new xArray(1,2,3); // [1,2,3]
  5. // Correctly checking for Array
  6. Array.isArray(arr); // true
  7. // Considered harmful, because doesn't work though iframes
  8. arr instanceof Array; // false

Polyfill

假如不存在 Array.isArray(),则在其他代码之前运行下面的代码将创建该方法。

  1. if (!Array.isArray) {
  2. Array.isArray = function(arg) {
  3. return Object.prototype.toString.call(arg) === '[object Array]';
  4. };
  5. }

Array.of()

根据一组参数来创建新的数组实例,支持任意的参数数量和类型。

Array.of() 方法创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型。

Array.of()Array 构造函数之间的区别在于处理整数参数:Array.of(7) 创建一个具有单个元素 7 的数组,而 Array(7) 创建一个长度为7的空数组(注意:这是指一个有7个空位(empty)的数组,而不是由7个undefined组成的数组)。

  1. Array.of(7); // [7]
  2. Array.of(1, 2, 3); // [1, 2, 3]
  3. Array(7); // [ , , , , , , ]
  4. Array(1, 2, 3); // [1, 2, 3]

语法

  1. Array.of(element0[, element1[, ...[, elementN]]])

参数

elementN

任意个参数,将按顺序成为返回数组中的元素。

返回值

新的 Array 实例。

描述

此函数是ECMAScript 2015标准的一部分。详见 Array.of 和 Array.from proposalArray.of polyfill

示例

  1. Array.of(1); // [1]
  2. Array.of(1, 2, 3); // [1, 2, 3]
  3. Array.of(undefined); // [undefined]

兼容旧环境

如果原生不支持的话,在其他代码之前执行以下代码会创建 Array.of() 。

  1. if (!Array.of) {
  2. Array.of = function() {
  3. return Array.prototype.slice.call(arguments);
  4. };
  5. }

Array.prototype.concat()

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

  1. const array1 = ['a', 'b', 'c'];
  2. const array2 = ['d', 'e', 'f'];
  3. const array3 = array1.concat(array2);
  4. console.log(array3);
  5. // expected output: Array ["a", "b", "c", "d", "e", "f"]

语法

  1. var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])

参数

value_N | 可选

将数组和/或值连接成新数组。如果省略了valueN参数参数,则concat会返回一个它所调用的已存在的数组的浅拷贝。详情请参阅下文描述。

返回值

新的 Array 实例。

描述

concat方法创建一个新的数组,它由被调用的对象中的元素组成,每个参数的顺序依次是该参数的元素(如果参数是数组)或参数本身(如果参数不是数组)。它不会递归到嵌套数组参数中。

concat方法不会改变this或任何作为参数提供的数组,而是返回一个浅拷贝,它包含与原始数组相结合的相同元素的副本。 原始数组的元素将复制到新数组中,如下所示:

  • 对象引用(而不是实际对象):concat将对象引用复制到新数组中。 原始数组和新数组都引用相同的对象。 也就是说,如果引用的对象被修改,则更改对于新数组和原始数组都是可见的。 这包括也是数组的数组参数的元素。
  • 数据类型如字符串,数字和布尔(不是StringNumberBoolean 对象):concat将字符串和数字的值复制到新数组中。

注意:数组/值在连接时保持不变。此外,对于新数组的任何操作(仅当元素不是对象引用时)都不会对原始数组产生影响,反之亦然。

示例

连接两个数组

以下代码将两个数组合并为一个新数组:

  1. var alpha = ['a', 'b', 'c'];
  2. var numeric = [1, 2, 3];
  3. alpha.concat(numeric);
  4. // result in ['a', 'b', 'c', 1, 2, 3]

连接三个数组

以下代码将三个数组合并为一个新数组:

  1. var num1 = [1, 2, 3],
  2. num2 = [4, 5, 6],
  3. num3 = [7, 8, 9];
  4. var nums = num1.concat(num2, num3);
  5. console.log(nums);
  6. // results in [1, 2, 3, 4, 5, 6, 7, 8, 9]

将值连接到数组

以下代码将三个值连接到数组:

  1. var alpha = ['a', 'b', 'c'];
  2. var alphaNumeric = alpha.concat(1, [2, 3]);
  3. console.log(alphaNumeric);
  4. // results in ['a', 'b', 'c', 1, 2, 3]

合并嵌套数组

以下代码合并数组并保留引用:

  1. var num1 = [[1]];
  2. var num2 = [2, [3]];
  3. var num3=[5,[6]];
  4. var nums = num1.concat(num2);
  5. console.log(nums);
  6. // results is [[1], 2, [3]]
  7. var nums2=num1.concat(4,num3);
  8. console.log(nums2)
  9. // results is [[1], 4, 5,[6]]
  10. // modify the first element of num1
  11. num1[0].push(4);
  12. console.log(nums);
  13. // results is [[1, 4], 2, [3]]

Array.prototype.copyWithin()

copyWithin() 方法浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。

  1. const array1 = ['a', 'b', 'c', 'd', 'e'];
  2. // copy to index 0 the element at index 3
  3. console.log(array1.copyWithin(0, 3, 4));
  4. // expected output: Array ["d", "b", "c", "d", "e"]
  5. // copy to index 1 all elements from index 3 to the end
  6. console.log(array1.copyWithin(1, 3));
  7. // expected output: Array ["d", "d", "e", "d", "e"]

语法

  1. arr.copyWithin(target[, start[, end]])

参数
target

0 为基底的索引,复制序列到该位置。如果是负数,target 将从末尾开始计算。

如果 target 大于等于 arr.length,将会不发生拷贝。如果 target 在 start 之后,复制的序列将被修改以符合 arr.length(复制之后数组长度等于arr.length。)

start

0 为基底的索引,开始复制元素的起始位置。如果是负数,start 将从末尾开始计算。

如果 start 被忽略,copyWithin 将会从0开始复制。

end

0 为基底的索引,开始复制元素的结束位置。copyWithin 将会拷贝到该位置,但不包括 end 这个位置的元素。如果是负数, end 将从末尾开始计算。

如果 end 被忽略,copyWithin 方法将会一直复制至数组结尾(默认为 arr.length)。

返回值

改变后的数组。

描述

参数 target、start 和 end 必须为整数。

如果 start 为负,则其指定的索引位置等同于 length+start,length 为数组的长度。end 也是如此。

copyWithin 方法不要求其 this 值必须是一个数组对象;除此之外,copyWithin 是一个可变方法,它可以改变 this 对象本身,并且返回它,而不仅仅是它的拷贝。

copyWithin 就像 C 和 C++ 的 memcpy 函数一样,且它是用来移动 Array 或者 TypedArray 数据的一个高性能的方法。复制以及粘贴序列这两者是为一体的操作;即使复制和粘贴区域重叠,粘贴的序列也会有拷贝来的值。

copyWithin 函数被设计为通用式的,其不要求其 this 值必须是一个数组对象。

copyWithin 是一个可变方法,它不会改变 this 的长度 length,但是会改变 this 本身的内容,且需要时会创建新的属性。

示例

  1. let numbers = [1, 2, 3, 4, 5];
  2. numbers.copyWithin(-2);
  3. // [1, 2, 3, 1, 2]
  4. numbers.copyWithin(0, 3);
  5. // [4, 5, 3, 4, 5]
  6. numbers.copyWithin(0, 3, 4);
  7. // [4, 2, 3, 4, 5]
  8. numbers.copyWithin(-2, -3, -1);
  9. // [1, 2, 3, 3, 4]
  10. [].copyWithin.call({length: 5, 3: 1}, 0, 3);
  11. // {0: 1, 3: 1, length: 5}
  12. // ES2015 Typed Arrays are subclasses of Array
  13. var i32a = new Int32Array([1, 2, 3, 4, 5]);
  14. i32a.copyWithin(0, 2);
  15. // Int32Array [3, 4, 5, 4, 5]
  16. // On platforms that are not yet ES2015 compliant:
  17. [].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4);
  18. // Int32Array [4, 2, 3, 4, 5]

Polyfill

  1. if (!Array.prototype.copyWithin) {
  2. Array.prototype.copyWithin = function(target, start/*, end*/) {
  3. // Steps 1-2.
  4. if (this == null) {
  5. throw new TypeError('this is null or not defined');
  6. }
  7. var O = Object(this);
  8. // Steps 3-5.
  9. var len = O.length >>> 0;
  10. // Steps 6-8.
  11. var relativeTarget = target >> 0;
  12. var to = relativeTarget < 0 ?
  13. Math.max(len + relativeTarget, 0) :
  14. Math.min(relativeTarget, len);
  15. // Steps 9-11.
  16. var relativeStart = start >> 0;
  17. var from = relativeStart < 0 ?
  18. Math.max(len + relativeStart, 0) :
  19. Math.min(relativeStart, len);
  20. // Steps 12-14.
  21. var end = arguments[2];
  22. var relativeEnd = end === undefined ? len : end >> 0;
  23. var final = relativeEnd < 0 ?
  24. Math.max(len + relativeEnd, 0) :
  25. Math.min(relativeEnd, len);
  26. // Step 15.
  27. var count = Math.min(final - from, len - to);
  28. // Steps 16-17.
  29. var direction = 1;
  30. if (from < to && to < (from + count)) {
  31. direction = -1;
  32. from += count - 1;
  33. to += count - 1;
  34. }
  35. // Step 18.
  36. while (count > 0) {
  37. if (from in O) {
  38. O[to] = O[from];
  39. } else {
  40. delete O[to];
  41. }
  42. from += direction;
  43. to += direction;
  44. count--;
  45. }
  46. // Step 19.
  47. return O;
  48. };
  49. }

Array.prototype.entries()

entries() 方法返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。

  1. const array1 = ['a', 'b', 'c'];
  2. const iterator1 = array1.entries();
  3. console.log(iterator1.next())
  4. expected output: Object { value: Array [0, "a"], done: false }
  5. console.log(iterator1.next().value);
  6. // expected output: Array [0, "a"]
  7. console.log(iterator1.next().value);
  8. // expected output: Array [1, "b"]

语法

  1. arr.entries()

返回值

一个新的 Array 迭代器对象。Array Iterator是对象,它的原型(proto:Array Iterator)上有一个next方法,可用用于遍历迭代器取得原数组的[key,value]。

示例

1、 Array Iterator

  1. var arr = ["a", "b", "c"];
  2. var iterator = arr.entries();
  3. console.log(iterator);
  4. /*Array Iterator {}
  5. __proto__:Array Iterator
  6. next:ƒ next()
  7. Symbol(Symbol.toStringTag):"Array Iterator"
  8. __proto__:Object
  9. */

2、iterator.next()

  1. var arr = ["a", "b", "c"];
  2. var iterator = arr.entries();
  3. console.log(iterator.next());
  4. /*{value: Array(2), done: false}
  5. done:false
  6. value:(2) [0, "a"]
  7. __proto__: Object
  8. */
  9. // iterator.next()返回一个对象,对于有元素的数组,
  10. // 是next{ value: Array(2), done: false };
  11. // next.done 用于指示迭代器是否完成:在每次迭代时进行更新而且都是false,
  12. // 直到迭代器结束done才是true。
  13. // next.value是一个["key","value"]的数组,是返回的迭代器中的元素值。

3、iterator.next方法运行

  1. var arr = ["a", "b", "c"];
  2. var iter = arr.entries();
  3. var a = [];
  4. // for(var i=0; i< arr.length; i++){ // 实际使用的是这个
  5. for(var i=0; i< arr.length+1; i++){ // 注意,是length+1,比数组的长度大
  6. var tem = iter.next(); // 每次迭代时更新next
  7. console.log(tem.done); // 这里可以看到更新后的done都是false
  8. if(tem.done !== true){ // 遍历迭代器结束done才是true
  9. console.log(tem.value);
  10. a[i]=tem.value;
  11. }
  12. }
  13. console.log(a); // 遍历完毕,输出next.value的数组

4、二维数组按行排序

  1. function sortArr(arr) {
  2. var goNext = true;
  3. var entries = arr.entries();
  4. while (goNext) {
  5. var result = entries.next();
  6. if (result.done !== true) {
  7. result.value[1].sort((a, b) => a - b);
  8. goNext = true;
  9. } else {
  10. goNext = false;
  11. }
  12. }
  13. return arr;
  14. }
  15. var arr = [[1,34],[456,2,3,44,234],[4567,1,4,5,6],[34,78,23,1]];
  16. sortArr(arr);
  17. /*(4) [Array(2), Array(5), Array(5), Array(4)]
  18. 0:(2) [1, 34]
  19. 1:(5) [2, 3, 44, 234, 456]
  20. 2:(5) [1, 4, 5, 6, 4567]
  21. 3:(4) [1, 23, 34, 78]
  22. length:4
  23. __proto__:Array(0)
  24. */

5、使用for…of 循环

  1. var arr = ["a", "b", "c"];
  2. var iterator = arr.entries();
  3. // undefined
  4. for (let e of iterator) {
  5. console.log(e);
  6. }
  7. // [0, "a"]
  8. // [1, "b"]
  9. // [2, "c"]

Array.prototype.every()

every() 方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。

注意:若收到一个空数组,此方法在一切情况下都会返回 true。

  1. const isBelowThreshold = (currentValue) => currentValue < 40;
  2. const array1 = [1, 30, 39, 29, 10, 13];
  3. console.log(array1.every(isBelowThreshold));
  4. // expected output: true

语法

  1. arr.every(callback[, thisArg])

参数

callback

用来测试每个元素的函数,它可以接收三个参数:

element

用于测试的当前值。

index | 可选

用于测试的当前值的索引。

array | 可选

调用 every 的当前数组。

thisArg

执行 callback 时使用的 this 值。

返回值

如果回调函数的每一次返回都为 truthy 值,返回 true ,否则返回 false

描述

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

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

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

every 不会改变原数组。

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

every 和数学中的”所有”类似,当所有的元素都符合条件才会返回true。正因如此,若传入一个空数组,无论如何都会返回 true。(这种情况属于无条件正确:正因为一个空集合没有元素,所以它其中的所有元素都符合给定的条件。)

数组实例

所有数组实例都会从 Array.prototype 继承属性和方法。修改 Array 的原型会影响到所有的数组实例。

Array.prototype 属性表示 Array 构造函数的原型,并允许您向所有Array对象添加新的属性和方法。

  1. /*
  2. 如果JavaScript本身不提供 first() 方法,
  3. 添加一个返回数组的第一个元素的新方法。
  4. */
  5. if(!Array.prototype.first) {
  6. Array.prototype.first = function() {
  7. console.log(`如果JavaScript本身不提供 first() 方法,
  8. 添加一个返回数组的第一个元素的新方法。`);
  9. return this[0];
  10. }
  11. }

描述

Array实例继承自 Array.prototype 。与所有构造函数一样,您可以更改构造函数的原型对象,以对所有 Array 实例进行更改。例如,可以添加新方法和属性以扩展所有Array对象。这用于 polyfilling, 例如。

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

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

属性

Array.prototype.constructor

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

Array.prototype.length

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

方法

修改器方法

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

Array.prototype.copyWithin()

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

Array.prototype.fill()

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

Array.prototype.pop()

删除数组的最后一个元素,并返回这个元素。

Array.prototype.push()

在数组的末尾增加一个或多个元素,并返回数组的新长度。

Array.prototype.reverse()

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

Array.prototype.shift()

删除数组的第一个元素,并返回这个元素。

Array.prototype.sort()

对数组元素进行排序,并返回当前数组。

Array.prototype.splice()

在任意的位置给数组添加或删除任意个元素。

Array.prototype.unshift()

在数组的开头增加一个或多个元素,并返回数组的新长度。

访问方法

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

Array.prototype.concat()

返回一个由当前数组和其它若干个数组或者若干个非数组值组合而成的新数组。

Array.prototype.includes()

判断当前数组是否包含某指定的值,如果是返回 true,否则返回 false。

Array.prototype.join()

连接所有数组元素组成一个字符串。

Array.prototype.slice()

抽取当前数组中的一段元素组合成一个新数组。

Array.prototype.toSource()

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

Array.prototype.toString()

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

Array.prototype.toLocaleString()

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

Array.prototype.indexOf()

返回数组中第一个与指定值相等的元素的索引,如果找不到这样的元素,则返回 -1。

Array.prototype.lastIndexOf()

返回数组中最后一个(从右边数第一个)与指定值相等的元素的索引,如果找不到这样的元素,则返回 -1。

迭代方法

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

Array.prototype.forEach()

为数组中的每个元素执行一次回调函数。

Array.prototype.entries()

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

Array.prototype.every()

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

Array.prototype.some()

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

Array.prototype.filter()

将所有在过滤函数中返回 true 的数组元素放进一个新数组中并返回。

Array.prototype.find()

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

Array.prototype.findIndex()

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

Array.prototype.keys()

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

Array.prototype.map()

返回一个由回调函数的返回值组成的新数组。

Array.prototype.reduce()

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

Array.prototype.reduceRight()

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

Array.prototype.values()

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

Array.prototype@@iterator)

和上面的 values() 方法是同一个函数。

示例

创建数组

下面这个例子创建了一个长度为 0 的数组 msgArray,然后给 msgArray[0] 和 msgArray[99] 赋值,从而导致数组长度变为了 100。

  1. var msgArray = [];
  2. msgArray[0] = 'Hello';
  3. msgArray[99] = 'world';
  4. if (msgArray.length === 100) {
  5. console.log('The length is 100.');
  6. }

创建二维数组

下面的例子创建了一个代表国际象棋棋盘的二维数组,然后将 (6, 4) 上的 Pawn (卒)拷贝到 (4, 4) 位置,而原本 (6, 4) 位置则被设置为空格。

  1. var board = [
  2. ['R','N','B','Q','K','B','N','R'],
  3. ['P','P','P','P','P','P','P','P'],
  4. [' ',' ',' ',' ',' ',' ',' ',' '],
  5. [' ',' ',' ',' ',' ',' ',' ',' '],
  6. [' ',' ',' ',' ',' ',' ',' ',' '],
  7. [' ',' ',' ',' ',' ',' ',' ',' '],
  8. ['p','p','p','p','p','p','p','p'],
  9. ['r','n','b','q','k','b','n','r'] ];
  10. console.log(board.join('\n') + '\n\n');
  11. // Move King's Pawn forward 2
  12. board[4][4] = board[6][4];
  13. board[6][4] = ' ';
  14. console.log(board.join('\n'));

下面是输出:

  1. R,N,B,Q,K,B,N,R
  2. P,P,P,P,P,P,P,P
  3. , , , , , , ,
  4. , , , , , , ,
  5. , , , , , , ,
  6. , , , , , , ,
  7. p,p,p,p,p,p,p,p
  8. r,n,b,q,k,b,n,r
  9. R,N,B,Q,K,B,N,R
  10. P,P,P,P,P,P,P,P
  11. , , , , , , ,
  12. , , , , , , ,
  13. , , , ,p, , ,
  14. , , , , , , ,
  15. p,p,p,p, ,p,p,p
  16. r,n,b,q,k,b,n,r

用数组将一组值以表格形式显示

  1. values = [];
  2. for (var x = 0; x < 10; x++){
  3. values.push([
  4. 2 ** x,
  5. 2 * x ** 2
  6. ])
  7. };
  8. console.table(values)

结果为:

  1. 0 1 0
  2. 1 2 2
  3. 2 4 8
  4. 3 8 18
  5. 4 16 32
  6. 5 32 50
  7. 6 64 72
  8. 7 128 98
  9. 8 256 128
  10. 9 512 162

(第一列为索引)