索引集合是一种数据结构,其中的元素使用编号索引存储和访问。存储在索引集合中的值被分配从 0
开始的编号索引,这种模式称为“零索引”。然后,您可以通过引用索引来访问存储在索引集合中的值。
数组
数组是一个容器,可以容纳零个或多个任何数据类型的值,包括复杂对象或其他数组。存储在数组中的值有时称为数组的“元素”。
创建数组
与原始数据类型一样,创建数组有两种方法:作为数组字面量,或通过使用 new Array()
调用 JavaScript 的内置 Array()
构造函数。将数组分配给变量提供了一种高度可移植且可迭代的方式,可将多个值分配给单个标识符。
数组字面量语法使用一组方括号 ([]
) 包围零个或多个逗号分隔的数据值
const myArray = [];
数组构造函数语法使用 JavaScript 的内置 Array
对象作为构造函数,并使用 new
关键字
const myArray = new Array();
数组字面量和数组构造函数语法都允许您在创建数组时使用信息填充数组,尽管这两种语法在定义这些值的方式上略有不同。数组字面量语法在方括号之间使用逗号分隔的值,这看起来与生成的数组相同
const myArray = [ true, null, "String", false ];
myArray;
> [ true, null, "String", false ]
数组构造函数语法将逗号分隔的值作为参数,但有一个特殊的行为例外
const myArray = new Array( true, null, "String", false );
myArray;
> Array(4) [ true, null, "String", false ]
当单个数值传递给 Array
构造函数时,该值不会分配给结果数组中的第零个位置。相反,会创建一个具有该数量空槽位的数组来存储值。这不会对数组施加任何限制。可以像使用数组字面量一样向其中添加和删除项。
// Firefox:\
const myArray = new Array( 10 );
myArray;
> Array(10) [ <10 empty slots> ]
// Chrome:
const myArray = new Array( 10 );
myArray;
> (10) [empty × 10]
包含空槽位的数组(有时称为“稀疏数组”)是特殊情况。空槽位通常(但不总是)被视为语言中其他地方的 undefined
值,而不是包含 undefined
或显式 null
值。
您可以通过在创建数组字面量时省略逗号之间的值,意外地使用数组字面量语法创建稀疏数组
const myArray = [ true,, true, false ];
myArray;
> Array(4) [ true, <1 empty slot>, true, false ]
尽管空槽位在所有上下文中都不被视为有意义的值,但它仍会被计入数组的总长度,这可能会在迭代数组的值时导致意外结果
const myArray = [ 1,, 3, 4 ];
myArray.length;
> 4
for( const myValue of myArray ) {
console.log( myValue + 10 );
}
> 11
> NaN
> 13
> 14
此行为是 JavaScript 早期一些设计决策的遗留问题。在现代开发中避免使用稀疏数组。
与原始类型一样,数组字面量从其对应的构造函数继承属性和方法。由于数组是对象的特殊形式,因此数组字面量语法和 new Array()
语法创建的功能相同的结果:一个从 Array
构造函数继承其原型的对象。
const arrayLiteral = [];
const arrayConstructor = new Array();
typeof arrayLiteral;
> "object"
arrayLiteral;
> Array []
length: 0
<prototype>: Array []
typeof arrayConstructor;
> "object"
arrayConstructor;
> Array []
length: 0
<prototype>: Array []
由于这两个结果是相同的,并且数组字面量语法更简洁且更字面化,因此我们强烈建议始终使用数组字面量语法而不是 new Array()
语法。
访问数组值
您可以使用方括号表示法访问数组中的各个元素,方括号表示法是一组方括号 ([]
),位于数组或其标识符之后,其中包含一个数字,该数字引用该元素的索引
[ "My string", "My other string" ][ 1 ];
> "My other string"
const myArray = [ "My string", 50, true ];
myArray[ 0 ];
> "My string"
myArray[ 1 ];
> 50
myArray[ 2 ];
> true
JavaScript 中的数组不是关联数组,这意味着您不能使用任意字符串作为索引。但是,用于访问数组中元素的数值会在后台强制转换为字符串值,这意味着您可以使用仅包含数字字符的字符串值
const myArray = [ "My string", 50, true ];
myArray[ 2 ];
> true
myArray[ "2" ];
> true
尝试访问数组中未定义的元素会导致 undefined
,而不是错误
const myArray = [ "My string", 50, true ];
myArray[ 9 ];
> undefined
解构赋值
解构赋值是一种从数组或对象中提取一系列值并将它们分配给一组标识符的简洁方法,此过程有时称为“解包”原始数据结构,尽管它不会修改原始数组或对象。
解构赋值使用类似数组或对象的标识符列表来跟踪值。在其最简单的形式(称为绑定模式解构)中,每个值都从数组或对象中解包并分配给相应的变量,并使用 let
或 const
(或 var
)初始化。
const myArray = [ "A string", "A second string" ];
const [ myFirstElement, mySecondElement ] = myArray;
const myObject = { firstValue: false, secondValue: true };
const { myProp, mySecondProp } = myObject;
myFirstElement;
> "My string"
mySecondElement;
> "Second string"
myProp;
> false
mySecondProp;
> true
使用花括号 ({}
) 解构对象,并使用方括号 ([]
) 解构数组。
const myArray = [ false, true ];
const myObject = { firstValue: false, secondValue: true };
const [ myProp, mySecondProp ] = myObject;
> Uncaught TypeError: myObject is not iterable
const { myElement, mySecondElement } = myArray;
myElement
> undefined
mySecondElement;
> undefined
数组的解构按顺序(从左到右)进行。解构赋值中的每个标识符都对应于数组中具有相同索引的元素
const myArray = [ 1, 2, 3 ];
const [ myElement, mySecondElement, myThirdElement ] = myArray;
myElement;
> 1
mySecondElement;
> 2
myThirdElement;
> 3
这也是解构对象时的默认行为。但是,如果解构赋值中使用的标识符与对象属性的键匹配,则这些标识符将填充相应的属性值,而与它们在其中指定的顺序无关
const myObject = { firstValue: 1, secondValue: 2, thirdValue 3 };
const { secondValue, thirdValue, firstValue } = myObject;
firstValue;
> 1
secondValue;
> 2
thirdValue;
> 3
可以通过省略标识符来跳过元素
const myArray = [ 1, 2, 3 ];
const [ firstValue,, secondValue ] = myArray;
firstValue;
> 1
secondValue;
> 3
解构语法还允许您在解构值是空槽位(如稀疏数组的情况)或 undefined
值的情况下分配默认值。
const myArray = [ true, ];
const [ firstValue = "Default string.", secondValue = "Default string." ] = myArray;
firstValue;
> true
secondValue;
> "Default string."
解构不会将值强制转换为特定类型。这意味着“假值”,例如空字符串 (""
) 或 null
,仍然被视为有意义的解构值
const myArray = [ false, null, 0, "",, undefined ];
const [ falseValue = true, nullValue = true, zeroValue = true, emptyStringValue = true, emptySlot = true, undefinedValue = true ] = myArray;
falseValue;
> false;
nullValue;
> null
zeroValue;
> 0
emptyStringValue;
> ""
emptySlot;
> true
undefinedValue;
> true
展开运算符
使用展开运算符 (...
),它在 ES6 中引入,用于将可迭代数据结构(例如数组、字符串或对象字面量)展开为单个元素。展开运算符紧跟其后是要展开的数据结构或包含该数据结构的变量的标识符。
const myArray = [ 1, 2, 3 ];
console.log( ...myArray );
> 1 2 3
展开语法主要用于复制和组合数组
const myArray = [ 4, 5, 6 ];
const mySecondArray = [1, 2, 3, ...myArray ];
mySecondArray;
> Array(6) [ 1, 2, 3, 4, 5, 6 ]
您只能在以下上下文中使用展开语法
对于数组和字符串,展开语法仅适用于函数调用中需要零个或多个参数或数组中需要元素的情况。本节中展开运算符语法的第一个示例之所以有效,是因为它将 ...myArray
作为参数传递给内置的 console.log
方法。
例如,您不能将正在展开的数据分配给另一个数组外部的变量
const myArray = [ 1, 2, 3 ];
const spreadVariable = ...myArray;
> Uncaught SyntaxError: Unexpected token '...'
但是,您可以通过将原始数组展开到数组字面量中来复制数组
const myArray = [ 1, 2, 3 ];
const spreadArray = [ ...myArray ];
spreadArray;
> Array(3) [ 1, 2, 3 ]
要将构成两个或多个数组的元素合并到单个数组中
const myArray = [ 1, 2, 3 ];
const mySecondArray = [ 4, 5, 6 ];
const myNewArray = [ ...myArray, ...mySecondArray ];
myNewArray;
> Array(6) [ 1, 2, 3, 4, 5, 6 ]
或在函数调用中将数组的元素作为单独的参数传递
const myArray = [ true, false ];
const myFunction = ( myArgument, mySecondArgument ) => {
console.log( myArgument, mySecondArgument );
};
myFunction( ...myArray );
> true false
展开运算符已扩展为可在ES2018 中的对象字面量中使用。与数组一样,您可以使用展开运算符来复制或合并对象
const myObj = { myProperty : true };
const mySecondObj = { ...myObj };
mySecondObj;
> Object { myProperty: true }
const myFirstObj = { myProperty : true };
const mySecondObj = { additionalProperty : true };
const myMergedObj = { ...myFirstObj, ...mySecondObj };
myMergedObj;
> Object { myProperty: true, additionalProperty: true }
展开运算符创建“浅”副本。这意味着它不会复制原始对象的原型和不可枚举属性。
const myCustomPrototype = { protoProp: "My prototype." };
const myObj = Object.create( myCustomPrototype, {
myEnumerableProp: {
value: true,
enumerable: true
},
myNonEnumerableProp: {
value: false,
enumerable: false
}
});
const myNewObj = { ...myObj };
myObj;
> Object { myEnumerableProp: true, … }
myEnumerableProp: true
myNonEnumerableProp: false
<prototype>: Object { protoProp: "My prototype." }
myNewObj;
> Object { myEnumerableProp: true }
myEnumerableProp: true
<prototype>: Object { … }
请记住,数组和对象不能互换使用。您不能将对象展开到数组中,也不能将数组展开到对象中。
剩余运算符
尽管运算符本身的语法相同,但剩余运算符 (...
) 根据其使用的上下文执行相反的功能。剩余运算符不会像在解构赋值中或作为函数参数那样将可迭代数据结构展开为单个元素,而是将元素组合到可迭代数据结构中。名称的由来是因为它用于收集一组数据值的“剩余”部分。
当与解构赋值一起使用时,该语法称为“剩余属性”语法。
const myArray = [ "First", "Second", "Third", "Fourth", "Fifth" ];
[ myFirstElement, mySecondElement, ...remainingElements ] = myArray;
myFirstElement;
> "First"
mySecondElement;
> "Second"
remainingElements;
> Array(3) [ "Third", "Fourth", "Fifth"]
当用于为函数提供不确定数量的参数时,该语法称为“剩余参数”语法
function myFunction( ...myParameters ) {
let result = 0;
myParameters.forEach( ( myParam ) => {
result += myParam;
});
return result;
};
myFunction( 2, 2 );
> 4
myFunction( 1, 1, 1, 10, 5 );
> 18
myFunction( 10, 11, 25 );
> 46
%TypedArray%
类型化数组是 ES6 功能,旨在存储结构化二进制数据,例如在处理上传的文件或 WebGL 时。
与符号一样,%TypedArray%
内部函数(通常记录为 %TypedArray%
或 @@TypedArray
,因此不会将其误认为是全局属性)在传统意义上不是构造函数,您不能使用 new
调用它或直接调用它。相反,%TypedArray%
指的是各个构造函数的父超类,每个构造函数都使用特定的二进制数据格式。内部 %TypedArray%
超类提供所有 %TypedArray%
构造函数子类及其实例继承的属性和实用程序方法。
检查您的理解情况
给定 `const myArray = [ 30, 50, 70 ];`,`myArray[1]` 返回什么?
70
如果 `myArray` 有三个值,那么 `myArray[9]` 返回什么?
Undefined
9
Null