引用类型之数组(Array)

189 阅读19分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天,点击查看活动详情

在前面的值类型和引用类型中我们已经简单地介绍了什么是数组以及数组的常见操作,这篇文章我们将深入且详细介绍一下数组。

js数组的长度和元素类型都是不固定的,因此JavaScript数组不一定是密集型的。除了我们经常使用的数组外,数组还分为类型数组和关联数组。 使用非整数并通过方括号或点号来访问或设置数组元素时,所操作的并不是数组列表中的元素,而是数组对象的 属性集合上的变量。数组对象的属性和数组元素列表是分开存储的,并且数组的遍历和修改操作也不能作用于这些命名属性。

类型数组

类型数组也称为类型化数组,是一种类似数组的对象,并提供了一种用于在内存缓冲区中访问原始二进制数据的机制。随着web应用程序功能越来越强大,需要处理和操作原始二进制数据,而JavaScript普通数组没法处理二进制数据,因此出现了类型化数组。

需要注意的是并不是所有用于普通数组的方法都能被类型化数组所支持,可以通过Array.isArray()来判断是真正的数组还是类型化数组,类型数组会返回false, 真正的数组会返回true。

1. 类型数组架构

JavaScript类型化数组将实现拆分为缓冲和视图两部分。缓冲(由ArrayBuffer对象实现)描述的是一个数据分块。为了访问在缓冲对象中包含的内存,需要使用视图。视图提供了上下文---即数据类型、起始偏移量和元素数---将数据转换为实际有类型的数组。

1.1 ArrayBuffer

ArrayBuffer是一种数据类型,用来表示一个通用的、固定长度的二进制数据缓冲区。如果要操作ArrayBuffer中的内容;你需要创建一个类型化数组的视图或一个描述缓冲数据格式的DataView。

1.2 类型化数组视图

类型化数组视图具有自描述性的名字和所有常用的数值类型像Int8、Uint32、Float64等等。有一种特殊类型的数组Unit8ClampedArray。它仅操作0到255之间的数组。

类型值范围字节数描述对应的Web IDL类型等效的c类型
Int8Array-128~12718 位有符号整数(补码)byteint8_t
Uint8Array0~25518 位无符号整数octetuint8_t
Uint8ClampedArray0~25518 位无符号整数(值会被裁剪)octetuint8_t
Int16Array-32768~32767216 位有符号整数(补码)shortint16_t
Uint16Array0~65535216 位有符号整数unsigned shortuint16_t
Int32Array-2147483648~2147483647432 位有符号整数(补码)longint32_t
Uint32Array0~4294967295432 位有符号整数unsigned longuint32_t
Float32Array-3.4E38~3.4E38 以及 1.2E-38(最小正数)432 位 IEEE 浮点数(7 位有效数字,例如 1.123456)unrestricted floatfloat
Float64Array-1.8E308~1.8E308 以及 5E-324(最小正数)864 位 IEEE 浮点数(16 位有效数字,例如 1.123...15)unrestricted doubledouble
BigInt64Array-2^63~2^63 - 1864 位有符号整数(补码)bigintint64_t (signed long long)
BigUint64Array0~2^64 - 1864 位无符号整数bigintuint64_t (unsigned long long)

1.3 DataView

DataView是一种底层接口,它提供有可以操作缓冲区中任意数据的访问器(getter/setter)API。

1.3.1 FileReader.readAsArrayBuffer()

FileReader 接口提供的 readAsArrayBuffer() 方法用于启动读取指定的 Blob 或 File 内容。当读取操作完成时,readyState 变成 DONE(已完成),并触发 loadend (en-US) 事件,同时 result 属性中将包含一个 ArrayBuffer 对象以表示所读取文件的数据。

语法

instanceOfFileReader.readAsArrayBuffer(blob);

参数

  • blob: 即将被读取的Blob或File对象。

XMLHttpRequest.prototype.send() XMLHttpRequest.send() 方法用于发送 HTTP 请求。如果是异步请求(默认为异步请求),则此方法会在请求发送后立即返回;如果是同步请求,则此方法直到响应到达后才会返回。XMLHttpRequest.send() 方法接受一个可选的参数,其作为请求主体;如果请求方法是 GET 或者 HEAD,则应将请求主体设置为 null。

语法

XMLHttpRequest.send(body)

参数

  • body: 在XHR请求中要发送的数据体。可以为以下情况
    • Document: 发送之前被序列化
    • XMLHttpRequestBodyInit:可以是Blob, BufferSource, FormData, URLSearchParams或者USVString对象。
    • null

1.3.2 ImageData.data

ImageData 接口描述 <canvas> 元素的一个隐含像素数据的区域。使用 ImageData() 构造函数创建或者使用和 canvas 在一起的 CanvasRenderingContext2D 对象的创建方法: createImageData() 和 getImageData()。也可以使用 putImageData() 设置 canvas 的一部分。

构造函数

ImageData() 三个参数,第一个 是Uint8ClampedArray的实例,第二个和第三个表示的是 width 和 height,必须保证 Uint8ClampedArray 的 length = 4widthheight 才不会报错,如果第一个参数 Uint8ClampedArray 没有的话,自动按照 width 和 height 的大小,以 0 填充整个像素矩阵。 使用给定的Uint8ClampedArray创建一个 ImageData 对象,并包含图像的大小。如果不给定数组,会创建一个“完全透明”(因为透明度值为 0) 的黑色矩形图像。注意,这是最常见的方式去创建这样一个对象,在 createImageData() 不可用时。

属性

以下属性都是只读属性

  • ImageData.data 只读
  • Uint8ClampedArray 描述了一个一维数组,包含以 RGBA 顺序的数据,数据使用 0 至 255(包含)的整数表示。
  • ImageData.height 只读 无符号长整型(unsigned long),使用像素描述 ImageData 的实际高度。
  • ImageData.width 只读 无符号长整型(unsigned long),使用像素描述 ImageData 的实际宽度。
2. 使用视图和缓冲

首先,我们创建一个16字节固定长度的缓冲

const buffer = new ArrayBuffer(16);

现在我们有了一段初始化为0的内存,目前还做不了什么太多操作。让我们确认一下数据的字节长度:

console.log(buffer.byteLength);   // 16

在实际开始操作这个缓冲之前,需要创建一个视图。

const init32View = new Int32Array(buffer);

然后就可以操作类型数组了

for (let i = 0; i < init32View.length; i++) {
  init32View[i] = i * 2;
}

init32View里面内容为:Int32Array(4) [0, 2, 4, 6, buffer: ArrayBuffer(16), byteLength: 16, byteOffset: 0, length: 4, Symbol(Symbol.toStringTag): 'Int32Array']

3. 给同一个数据创建多个视图
const int16View = new Int16Array(buffer);

for (let i = 0; i < int16View.length; i++) {
  console.log(`Entry ${i}: ${int16View[i]}`);
}

// 执行结果
Entry 0: 0
Entry 1: 0
Entry 2: 2
Entry 3: 0
Entry 4: 4
Entry 5: 0
Entry 6: 6
Entry 7: 0

这两个数组都是同一数据以不同格式展示出来的视图。

4. 转换为普通数组

在处理完一个类型化数组后,有时需要把它转为普通数组,以便可以从Array原型中受益。可以使用Array.from();、

通常有这么几种形式

  • Int8Array
  • Uint8Array
  • Uint8ClampedArray
  • Int16Array
  • Uint16Array
  • Int32Array
  • Uint32Array
  • Float32Array
  • Float64Array
  • DataView
5. 如何选择

如果存在下列场景,才选择使用类型化数组

  • 需要处理原始二进制数据
  • js引擎更易优化类型化数组,如果项目对数组的优化要求很高,建议使用类型化数组,因为js引擎不能保证普通数据永远都能得到优化

关联数组

具有命名索引的数组被称为被称为关联数组。当用户为数据类型为 Array 的键赋值时,它会转换为一个对象,并失去以前数据类型的属性和方法。关联数组使用字符串而不是数字作为索引。

let arr = [];
arr['name'] = 'Tom';
arr['age'] = 15;
console.log(arr.length);   // 0

需要特别注意的是自定义索引的关联数组的长度是0

普通数组

访问数组属性

以数字开头的属性不能用点号引用,必须用方括号。其他的可以使用点号引用。

let years = [1950, 1960, 1970, 1980, 1990, 2000, 2010]
console.log(years.0)   // a syntax error
console.log(years[0])  // works properly

你也可以将数组的索引用引号引起来,比如 years[0] 可以写成 years['0']

数组长度和数字下标的关系

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

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

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

fruits.length = 10
console.log(fruits)              // ['banana', 'apple', 'peach', empty x 2, 'mango', empty x 4]
console.log(Object.keys(fruits)) // ['0', '1', '2', '5']
console.log(fruits.length)       // 10
console.log(fruits[8])           // undefined

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

fruits.length = 2
console.log(Object.keys(fruits)) // ['0', '1']
console.log(fruits.length)       // 2
构造器

Array()构造器用于创建Array对象。

1. 语法

new Array(element0, element1, /* … ,*/ elementN)
new Array(arrayLength)

Array(element0, element1, /* … ,*/ elementN)
Array(arrayLength)

2. 参数

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

  • arrayLength: 如果传递给 Array 构造函数的唯一参数是 0 到 232 - 1(包括)之间的整数,这将返回一个新的 JavaScript 数组,其 length 属性设置为该数字(注意:这意味着一个 arrayLength 空槽数组,而不是具有实际 undefined 值的槽)。

3. 使用方法

// 字面量
const fruits = ['Apple', 'Banana'];

console.log(fruits.length); // 2
console.log(fruits[0]);     // "Apple"

// 单个参数, 一般是长度
const fruits = new Array(2);

console.log(fruits.length); // 2
console.log(fruits[0]);     // undefined

// 多个参数
let fruits = new Array('Apple', 'Banana');

console.log(fruits.length); // 2
console.log(fruits[0]);     // "Apple"
静态属性

和静态方法类似,是所有实例化对象共用的属性。Array[@@species]  访问器属性返回 Array 的构造函数。

1. 语法

Array[Symbol.species]

2. 使用

Array[Symbol.species]; // function Array()
静态方法

1. Array.from()

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

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

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

1.1 应用

// 类数组生成数组
function f() {
  return Array.from(arguments);
}

f(1, 2, 3);  // [ 1, 2, 3 ]

// 箭头函数
Array.from([1, 2, 3], x => x + x);  // [2, 4, 6]

2. Array.isArray()

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

2.1 使用

Array.isArray([1, 2, 3]);  // true
Array.isArray({foo: 123}); // false
Array.isArray('foobar');   // false
Array.isArray(undefined);  // false

3. Array.of()

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

3.1 使用

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

Array.of() 方法是一个通用的工厂方法。例如,如果 Array 的子类继承了 of() 方法,继承的 of() 方法将返回子类的新实例而不是 Array 实例。事实上,this 值可以是任何接受单个参数表示新数组长度的构造函数,并且构造函数将与传递给 of() 的参数数量一起被调用。当所有元素都被分配时,最终的 length 将再次设置。如果 this 值不是构造函数,则改用普通的 Array 构造函数。

实例属性

1. Array.length

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

1.1 使用

const listA = [1, 2, 3];
const listB = new Array(6);

console.log(listA.length);
// 3

console.log(listB.length);
// 6

2. Array.prototype[@@unscopables]

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

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

实例方法

1. Array.prototype.at()

at()  方法接收一个整数值并返回该索引对应的元素,允许正数和负数。负整数从数组中的最后一个元素开始倒数。

在传递非负数时,at() 方法等价于括号表示法。例如,array[0] 和 array.at(0) 均返回第一个元素。但是,当你需要从数组的末端开始倒数时,通常的做法是访问 length并将其减去从末端开始的相对索引。

const cart = ['apple', 'banana', 'pear'];
console.log(cart.at(-1));  // 'pear'

2. Array.prototype.concat()

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

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

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

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

2.1 使用

const letters = ['a', 'b', 'c'];
const numbers = [1, 2, 3];

const alphaNumeric = letters.concat(numbers);
console.log(alphaNumeric);
// results in ['a', 'b', 'c', 1, 2, 3]

3. Array.prototype.copyWithin()

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

3.1 语法

copyWithin(target)
copyWithin(target, start)
copyWithin(target, start, end)
  • 参数 target、start 和 end 必须为整数。
  • 如果 start 为负,则其指定的索引位置等同于 length+start,length 为数组的长度。end 也是如此。
  • copyWithin 方法不要求其 this 值必须是一个数组对象;除此之外,copyWithin 是一个可变方法,它可以改变 this 对象本身,并且返回它,而不仅仅是它的拷贝。
  • copyWithin是一个可变方法,它不会改变 this 的长度 length,但是会改变 this 本身的内容,且需要时会创建新的属性。

3.2 使用

[1, 2, 3, 4, 5].copyWithin(-2)   // [1, 2, 3, 1, 2]

[1, 2, 3, 4, 5].copyWithin(0, 3)   // [4, 5, 3, 4, 5]

4. Array.prototype.entries()

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

4. 1 使用

const a = ["a", "b", "c"];

for (const [index, element] of a.entries()) {
  console.log(index, element);
}

// 0 'a'
// 1 'b'
// 2 'c'

5. Array.prototype.every()

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

5.1 使用

[12, 5, 8, 130, 44].every(x => x >= 10); // false
[12, 54, 18, 130, 44].every(x => x >= 10); // true

6. Array.prototype.fill()

fill()  方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。

6.1 语法

fill(value)
fill(value, start)
fill(value, start, end)

fill 方法接受三个参数 valuestart 以及 endstart 和 end 参数是可选的,其默认值分别为 0 和 this 对象的 length 属性值。 如果 start 是个负数,则开始索引会被自动计算成为 length + start,其中 length 是 this 对象的 length 属性值。如果 end 是个负数,则结束索引会被自动计算成为 length + end

6.2 用法

[1, 2, 3].fill(4);               // [4, 4, 4]
[1, 2, 3].fill(4, 1);            // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2);         // [1, 4, 3]

7. Array.prototype.filter()

filter()  方法创建给定数组一部分的浅拷贝,其包含通过所提供函数实现的测试的所有元素。

7.1 语法

// 箭头函数
filter((element) => { /* … */ } )
filter((element, index) => { /* … */ } )
filter((element, index, array) => { /* … */ } )

// 回调函数
filter(callbackFn)
filter(callbackFn, thisArg)

// 内联回调函数
filter(function(element) { /* … */ })
filter(function(element, index) { /* … */ })
filter(function(element, index, array){ /* … */ })
filter(function(element, index, array) { /* … */ }, thisArg)

7.2 用法

function isBigEnough(value) {
  return value >= 10;
}

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

8. Array.prototype.find()

find()  方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 `undefined。

  • 如果需要在数组中找到对应元素的索引,请使用 findIndex()
  • 如果需要查找某个值的索引,请使用 Array.prototype.indexOf()。(它类似于 Array.prototype.indexOf(),但只是检查每个元素是否与值相等,而不是使用测试函数。)
  • 如果需要查找数组中是否存在值,请使用 Array.prototype.includes()。同样,它检查每个元素是否与值相等,而不是使用测试函数。
  • 如果需要查找是否有元素满足所提供的测试函数,请使用 Array.prototype.some()

8.1 语法

// 箭头函数
find((element) => { /* … */ } )
find((element, index) => { /* … */ } )
find((element, index, array) => { /* … */ } )

// 回调函数
find(callbackFn)
find(callbackFn, thisArg)

// 内联回调函数
find(function(element) { /* … */ })
find(function(element, index) { /* … */ })
find(function(element, index, array){ /* … */ })
find(function(element, index, array) { /* … */ }, thisArg)

8.2 用法

const inventory = [
  {name: 'apples', quantity: 2},
  {name: 'bananas', quantity: 0},
  {name: 'cherries', quantity: 5}
];

const result = inventory.find(({ name }) => name === 'cherries');

console.log(result) // { name: 'cherries', quantity: 5 }

9. Array.prototype.findIndex()

findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1。

9.1 语法

/ 箭头函数
findIndex((element) => { /* … */ } )
findIndex((element, index) => { /* … */ } )
findIndex((element, index, array) => { /* … */ } )

// 回调函数
findIndex(callbackFn)
findIndex(callbackFn, thisArg)

// 内联回调函数
findIndex(function(element) { /* … */ })
findIndex(function(element, index) { /* … */ })
findIndex(function(element, index, array){ /* … */ })
findIndex(function(element, index, array) { /* … */ }, thisArg)

9.2 用法

function isPrime(element, index, array) {
  var start = 2;
  while (start <= Math.sqrt(element)) {
    if (element % start++ < 1) {
      return false;
    }
  }
  return element > 1;
}

console.log([4, 6, 8, 12].findIndex(isPrime)); // -1, not found
console.log([4, 6, 7, 12].findIndex(isPrime)); // 2

10. Array.prototype.forEach()

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

语法同上

const items = ['item1', 'item2', 'item3'];
const copyItems = [];

// before
for (let i = 0; i < items.length; i++) {
  copyItems.push(items[i]);
}

// after
items.forEach((item) => {
  copyItems.push(item);
});

11. Array.prototype.includes()

includes()  方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回 false

11.1 语法

includes(searchElement)
includes(searchElement, fromIndex)

11.2 用法

[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

12. Array.prototype.indexOf()

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

语法同上

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

13. Array.prototype.join()

join()  方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串,用逗号或指定的分隔符字符串分隔。如果数组只有一个元素,那么将返回该元素而不使用分隔符。

13.1 语法

join()
join(separator)

13.2 用法

const a = ['Wind', 'Water', 'Fire'];
a.join();      // 'Wind,Water,Fire'
a.join(', ');  // 'Wind, Water, Fire'
a.join(' + '); // 'Wind + Water + Fire'
a.join('');    // 'WindWaterFire'

14. Array.prototype.keys()

keys()  方法返回一个包含数组中每个索引键的 Array Iterator 对象。

var arr = ["a", , "c"];
var sparseKeys = Object.keys(arr);
var denseKeys = [...arr.keys()];
console.log(sparseKeys); // ['0', '2']
console.log(denseKeys);  // [0, 1, 2]

15. Array.prototype.lastIndexOf()

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

15.1 语法

lastIndexOf(searchElement)
lastIndexOf(searchElement, fromIndex)

15.2 用法

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

16. Array.prototype.map()

map()  方法创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成。

语法同filter

const numbers = [1, 4, 9];
const roots = numbers.map((num) => Math.sqrt(num));

// roots 现在是     [1, 2, 3]
// numbers 依旧是   [1, 4, 9]

17. Array.prototype.pop()

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

const myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];

const popped = myFish.pop();

console.log(myFish); // ['angel', 'clown', 'mandarin']

console.log(popped); // 'sturgeon'

18. Array.prototype.push()

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

18.1 语法

push(element0)
push(element0, element1)
push(element0, element1, /* … ,*/ elementN)

18.2 用法

var sports = ["soccer", "baseball"];
var total = sports.push("football", "swimming");

console.log(sports);
// ["soccer", "baseball", "football", "swimming"]

console.log(total);
// 4

19. Array.prototype.reduce()

reduce()  方法对数组中的每个元素按序执行一个由您提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值。

第一次执行回调函数时,不存在“上一次的计算结果”。如果需要回调函数从数组索引为 0 的元素开始执行,则需要传递初始值。否则,数组索引为 0 的元素将被作为初始值 initialValue,迭代器将从第二个元素开始执行(索引为 1 而不是 0)。

let sum = [0, 1, 2, 3].reduce(function (previousValue, currentValue) {
  return previousValue + currentValue
}, 0)
// sum is 6

20. Array.prototype.reduceRight()

reduceRight()  方法接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值。

语法和用法同上

21. Array.prototype.reverse()

reverse()  方法将数组中元素的位置颠倒,并返回该数组。数组的第一个元素会变成最后一个,数组的最后一个元素变成第一个。该方法会改变原数组。

const a = [1, 2, 3];

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

a.reverse();

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

22. Array.prototype.shift()

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

var myFish = ['angel', 'clown', 'mandarin', 'surgeon'];

console.log('myFish before:', JSON.stringify(myFish));
// myFish before: ['angel', 'clown', 'mandarin', 'surgeon']

var shifted = myFish.shift();

console.log('myFish after:', myFish);
// myFish after: ['clown', 'mandarin', 'surgeon']

console.log('Removed this element:', shifted);
// Removed this element: angel

23. Array.prototype.unshift()

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

let arr = [4, 5, 6];

arr.unshift(1, 2, 3);
console.log(arr);
// [1, 2, 3, 4, 5, 6]

24. Array.prototype.slice()

slice()  方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。

24.1 语法

slice()
slice(start)
slice(start, end)

slice 不会修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。原数组的元素会按照下述规则拷贝:

  • 如果该元素是个对象引用(不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变。
  • 对于字符串、数字及布尔值来说(不是 StringNumber 或者 Boolean对象),slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。

如果向两个数组任一中添加了新元素,则另一个不会受到影响。

24.2 用法

var fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];
var citrus = fruits.slice(1, 3);

// fruits contains ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango']
// citrus contains ['Orange','Lemon']

25. Array.prototype.splice()

splice()  方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。

25.1 语法

splice(start)
splice(start, deleteCount)
splice(start, deleteCount, item1)
splice(start, deleteCount, item1, item2, itemN)

如果添加进数组的元素个数不等于被删除的元素个数,数组的长度会发生相应的改变。 25.2 用法

var myFish = ["angel", "clown", "mandarin", "sturgeon"];
var removed = myFish.splice(2, 0, "drum");

// 运算后的 myFish: ["angel", "clown", "drum", "mandarin", "sturgeon"]
// 被删除的元素:[], 没有元素被删除

26. Array.prototype.sort()

sort()  方法用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的 UTF-16 代码单元值序列时构建的

26.1 语法

/ 无函数
sort()

// 箭头函数
sort((a, b) => { /* … */ } )

// 比较函数
sort(compareFn)

// 内联比较函数
sort(function compareFn(a, b) { /* … */ })

26.2 用法

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

27. Array.prototype.values()

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

const arr = ['a', 'b', 'c', 'd', 'e'];
const iterator = arr.values();
console.log(iterator);        // Array Iterator {  }
iterator.next().value;        // "a"
arr[1] = 'n';
iterator.next().value;        // "n"