Please note, this is a STATIC archive of website developer.mozilla.org from November 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

翻译正在进行中。

这个章节主要介绍了以索引进行排序的数据集合。包括数组以及类似于数组的数据结构,如 Array TypedArray 

数组对象(Array object)

数组(array)是一个有序的数据集合,我们可以通过数组名称(name)和索引(index)进行访问。例如,我们定义了一个数组emp,数组中的每个元素包含了一个雇员的名字以及其作为索引的员工号。那么emp[1]将会代表1号员工,emp[2]将会代表2号员工,以此类推。

JavaScript中没有明确的数组数据类型。但是,我们可以通过使用内置Array对象和它的方法对数组进行操作。Array对象有很多操作数组的方法,比如合并、反转、排序等。数组对象有一个决定数组长度和使用正则表达式操作其他属性的属性。

创建数组(creating an array)

以下语句创建等效的数组:

var arr = new Array(element0, element1, ..., elementN);
var arr = Array(element0, element1, ..., elementN);
var arr = [element0, element1, ..., elementN];

// 译者注: var arr=[4] 和 var arr=new Array(4)是不等效的,
// 后者4指数组长度,所以使用字面值(literal)的方式应该不仅仅是便捷,同时也不易踩坑

element0, element1, ..., elementN 是数组元素的值的列表。当这些值被指定后,数组将被初始化,他们将被作为数组元素。数组的length属性也会被设为参数的个数。

括号语法被称为 "数组字面值" 或 "数组初始化器", 它比其他创建数组的方式更便捷,所以通常是首选。详细内容参见 Array literals 。

为了创建一个长度不为0,但是又没有任何元素的数组,可选以下任何一种方式:

var arr = new Array(arrayLength);
var arr = Array(arrayLength);

// 这样有同样的效果
var arr = [];
arr.length = arrayLength;

注意: 以上代码中,数组长度(arrayLength)必须为一个数字(Number),其他情况下,将创建一个单元素的数组。调用 arr.length 将返回数组长度,但是数组实际上包含了空(未定义undefined)的元素。 在数组上运行 for...in 循环,将会返回数组元素的节点。

除了如上所示创建新定义的变量,数组(array)也可以作为一个属性(property)分配给一个新的或者已存在的对象(object):

var obj = {};
// ...
obj.prop = [element0, element1, ..., elementN];

// OR
var obj = {prop: [element0, element1, ...., elementN]}

如果你希望用单个元素初始化一个数组,而这个元素恰好又是数字(Number),那么你必须使用括号语法。当单个的数字(Number)传递给Array()构造函数时,将会被解释为数组长度,并非单个元素。

var arr = [42];      // Creates an array with only one element:
                     // the number 42.
var arr = Array(42); // Creates an array with no element, 
                     // but with arr.length set to 42

// The above code is equivalent to
var arr = [];
arr.length = 42;

如果N不是一个整数,调用Array(N)将会报RangeError错误, 以下方法说明了这种行为:

var arr = Array(9.3);  // RangeError: Invalid array length

如果你需要创建任意类型的单元素数组,安全的方式是使用字面值。或者在向数组添加单个元素之前先创建一个空的数组。

填充数组(populating an array)

你可以通过给元素赋值来填充数组,例如:

var emp = [];
emp[0] = "Casey Jones";
emp[1] = "Phil Lesh";
emp[2] = "August West";

注意:如果你在以上代码中给数组操作符的是一个非整形数值,那么将作为一个代表数组的对象的属性(property)创建,而非作为数组的元素。

var arr = [];
arr[3.4] = "Oranges";
console.log(arr.length);                // 0
console.log(arr.hasOwnProperty(3.4));   // true

你也可以在创建数组的时候去填充它:

var myArray = new Array("Hello", myVar, 3.14159);
var myArray = ["Mango", "Apple", "Orange"]

引用数组元素(referring to array elements)

你可以通过数组元素的序号去引用这个元素,例如,假设你定义了如下数组:

var myArray = ["Wind", "Rain", "Fire"];

你可以用 myArray[0]引用第一个元素,myArray[1]引用第二个元素。元素的索引是从0开始的。

注意:数组操作符(方括号 [ ])也可以用来访问数组的属性(在JavaScript中,数组也是对象)。例如:

var arr = ["one", "two", "three"];
arr[2];  // three
arr["length"];  // 3

理解 length

在实施层面, JavaScript实际上是将元素作为标准的对象属性来存储,把数组索引作为属性名。长度属性是特殊的,它总是返回最后一个元素的索引值加1(下例中, Dusty 的索引是30,所以cats.length 返回 30 + 1)。记住, JavaScript 数组索引是基于0的: 他们从0开始,而不是1。这意味着数组长度属性将比最大的索引值大1:

var cats = [];
cats[30] = ['Dusty'];
console.log(cats.length); // 31

你也可以分配length属性。写一个小于数组元素数量的值会缩短数组,写0会彻底清空数组:

var cats = ['Dusty', 'Misty', 'Twiggy'];
console.log(cats.length); // 3

cats.length = 2;
console.log(cats); // logs "Dusty,Misty" - Twiggy has been removed

cats.length = 0;
console.log(cats); // logs nothing; the cats array is empty

cats.length = 3;
console.log(cats); // [undefined, undefined, undefined]

遍历数组(interating over array)

遍历数组元素并以某种方式处理每个元素是一个常见的操作。以下是最简单的方式:

var colors = ['red', 'green', 'blue'];
for (var i = 0; i < colors.length; i++) {
  console.log(colors[i]);
}

如果你确定数组中没有一个元素的求值是false —— 如果你的数组只包含DOM节点,如下,你可以选择一个更高效的土法子:

var divs = document.getElementsByTagName('div');
for (var i = 0, div; div = divs[i]; i++) {
  /* Process div in some way */
}

这样避免了检测数组长度的开销,额外的好处是确保了div变量当前在每次循环中都被重新赋值为当前项。

forEach() 方法提供了遍历数组元素的其他方法:

var colors = ['red', 'green', 'blue'];
colors.forEach(function(color) {
  console.log(color);
});

被传递给forEach的函数会在数组的每个元素像上执行一次,元素作为参数传递给该函数。未赋值的值不会在forEach循环迭代。

注意,在数组定义时省略的元素不会在forEach遍历时被列出,但是手动赋值为undefined的元素是会被列出的:

var array = ['first', 'second', , 'fourth'];

// returns ['first', 'second', 'fourth'];
array.forEach(function(element) {
  console.log(element);
})

if(array[2] === undefined) { console.log('array[2] is undefined'); } // true

var array = ['first', 'second', undefined, 'fourth'];

// returns ['first', 'second', undefined, 'fourth'];
array.forEach(function(element) {
  console.log(element);
})

一旦 JavaScript 元素被保存为标准的对象属性,通过for...in 循环来迭代迭代将变得不明智,因为正常元素和所有可枚举的属性都会被列出。

数组的方法(array methods)

Array 对象具有下列方法:

concat() 连接两个数组并返回一个新的数组。

var myArray = new Array("1", "2", "3");
myArray = myArray.concat("a", "b", "c"); 
// myArray is now ["1", "2", "3", "a", "b", "c"]

join(deliminator = ',') 将数组的所有元素连接成一个字符串。

var myArray = new Array("Wind", "Rain", "Fire");
var list = myArray.join(" - "); // list is "Wind - Rain - Fire"

push() 在数组末尾添加一个或多个元素,并返回数组操作后的长度。

var myArray = new Array("1", "2");
myArray.push("3"); // myArray is now ["1", "2", "3"]

pop() 从数组移出最后一个元素,并返回该元素。

var myArray = new Array("1", "2", "3");
var last = myArray.pop(); 
// myArray is now ["1", "2"], last = "3"

shift() 从数组移出第一个元素,并返回该元素。

var myArray = new Array ("1", "2", "3");
var first = myArray.shift(); 
// myArray is now ["2", "3"], first is "1"

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

var myArray = new Array ("1", "2", "3");
myArray.unshift("4", "5"); 
// myArray becomes ["4", "5", "1", "2", "3"]

slice(start_index, upto_index) 从数组提取一个片段,并作为一个新数组返回。

var myArray = new Array ("a", "b", "c", "d", "e");
myArray = myArray.slice(1, 4); // starts at index 1 and extracts all elements
                               // until index 3, returning [ "b", "c", "d"]

splice(index, count_to_remove, addElement1, addElement2, ...)从数组移出一些元素,(可选)并替换它们。

var myArray = new Array ("1", "2", "3", "4", "5");
myArray.splice(1, 3, "a", "b", "c", "d"); 
// myArray is now ["1", "a", "b", "c", "d", "5"]
// This code started at index one (or where the "2" was), 
// removed 3 elements there, and then inserted all consecutive
// elements in its place.

reverse() 颠倒数组元素的顺序:第一个变成最后一个,最后一个变成第一个。

var myArray = new Array ("1", "2", "3");
myArray.reverse(); 
// transposes the array so that myArray = [ "3", "2", "1" ]

sort() 给数组元素排序。

var myArray = new Array("Wind", "Rain", "Fire");
myArray.sort(); 
// sorts the array so that myArray = [ "Fire", "Rain", "Wind" ]

sort() 也可以带一个回调函数来决定怎么比较数组元素。这个回调函数比较两个值,并返回3个值中的一个:

例如,下面的代码通过字符串的最后一个字母进行排序:

var sortFn = function(a, b){
  if (a[a.length - 1] < b[b.length - 1]) return -1;
  if (a[a.length - 1] > b[b.length - 1]) return 1;
  if (a[a.length - 1] == b[b.length - 1]) return 0;
}
myArray.sort(sortFn); 
// sorts the array so that myArray = ["Wind","Fire","Rain"]
  • 如果 a 小于 b ,返回 -1(或任何负数)
  • 如果 a 大于 b ,返回 1 (或任何正数)
  • 如果 ab 相等,返回 0。

indexOf(searchElement[, fromIndex]) 在数组中搜索searchElement 并返回第一个匹配的索引。

var a = ['a', 'b', 'a', 'b', 'a'];
console.log(a.indexOf('b')); // logs 1
// Now try again, starting from after the last match
console.log(a.indexOf('b', 2)); // logs 3
console.log(a.indexOf('z')); // logs -1, because 'z' was not found

lastIndexOf(searchElement[, fromIndex]) 和 indexOf差不多,但是是从结尾开始,并且是反向搜索。

var a = ['a', 'b', 'c', 'd', 'a', 'b'];
console.log(a.lastIndexOf('b')); // logs 5
// Now try again, starting from before the last match
console.log(a.lastIndexOf('b', 4)); // logs 1
console.log(a.lastIndexOf('z')); // logs -1

forEach(callback[, thisObject]) 在数组每个元素项上执行callback

var a = ['a', 'b', 'c'];
a.forEach(function(element) { console.log(element);} ); 
// logs each item in turn

map(callback[, thisObject]) 在数组的每个单元项上执行callback函数,并把返回包含回调函数返回值的新数组。》译者注:也就是遍历数组,并通过callback对数组元素进行操作,并将所有操作结果放入数组中并返回该数组。

var a1 = ['a', 'b', 'c'];
var a2 = a1.map(function(item) { return item.toUpperCase(); });
console.log(a2); // logs A,B,C

filter(callback[, thisObject]) 返回一个包含所有在回调函数上返回为true的元素的新数组。》译者注:callback在这里担任的是过滤器的角色,当元素符合条件,过滤器就返回true,而filter则会返回所有符合过滤条件的元素。

var a1 = ['a', 10, 'b', 20, 'c', 30];
var a2 = a1.filter(function(item) { return typeof item == 'number'; });
console.log(a2); // logs 10,20,30

every(callback[, thisObject]) 当数组中每一个元素在callback上被返回true时就返回true。》译者注:同上,every其实类似filter,只不过它的功能是判断是不是数组中的所有元素都符合条件,并且返回的是bool值。

function isNumber(value){
  return typeof value == 'number';
}
var a1 = [1, 2, 3];
console.log(a1.every(isNumber)); // logs true
var a2 = [1, '2', 3];
console.log(a2.every(isNumber)); // logs false

some(callback[, thisObject]) 只要数组中有一项在callback上被返回true,就返回true。》译者注:同上,类似every,不过前者要求都符合筛选条件才返回true,后者只要有符合条件的就返回true。

function isNumber(value){
  return typeof value == 'number';
}
var a1 = [1, 2, 3];
console.log(a1.some(isNumber)); // logs true
var a2 = [1, '2', 3];
console.log(a2.some(isNumber)); // logs true
var a3 = ['1', '2', '3'];
console.log(a3.some(isNumber)); // logs false

以上方法都带一个被称为迭代方法的的回调函数,因为他们以某种方式迭代整个数组。都有一个可选的第二参数 thisObject,如果提供了这个参数,thisObject 变成回调函数内部的 this 关键字的值。如果没有提供,例如函数在一个显示的对象上下文外被调用时,this 将引用全局对象(window).

实际上在调用回调函数时传入了3个参数。第一个是当前元素项的值,第二个是它在数组中的索引,第三个是数组本身的一个引用。 JavaScript 函数忽略任何没有在参数列表中命名的参数,因此提供一个只有一个参数的回调函数是安全的,例如 alert 。

reduce(callback[, initialValue]) 使用回掉函数 callback(firstValue, secondValue) 把数组列表计算成一个单一值(译者注:他数组元素两两递归处理的方式把数组计算成一个值)

var a = [10, 20, 30];
var total = a.reduce(function(first, second) { return first + second; }, 0);
console.log(total) // Prints 60

reduceRight(callback[, initalvalue])reduce()相似,但是是从最后一个元素开始的。

reducereduceRight 是迭代数组方法中最不被人熟知的两个函数.。他们应该使用在那些需要把数组的元素两两递归处理,并最终计算成一个单一结果的算法。

多维数组(multi-dimensional arrays)

数组是可以嵌套的, 这就意味着一个数组可以作为一个元素被包含在另外一个数组里面. 利用JavaScript数组的这个特性, 可以创建多维数组.

以下代码创建了一个二维数组.

var a = new Array(4);
for (i = 0; i < 4; i++) {
  a[i] = new Array(4);
  for (j = 0; j < 4; j++) {
    a[i][j] = "[" + i + "," + j + "]";
  }
}

这个例子创建的数组拥有以下行数据:

Row 0: [0,0] [0,1] [0,2] [0,3]
Row 1: [1,0] [1,1] [1,2] [1,3]
Row 2: [2,0] [2,1] [2,2] [2,3]
Row 3: [3,0] [3,1] [3,2] [3,3]

数组和正则表达式

当一个数组是一个正则表达式对一个字符串的匹配结果,这个数组返回属性和元素来提供正则匹配的信息。 RegExp.exec(), String.match() 和 String.split() 的返回值是一个数组。 使用数组和正则表达式的的更多信息, 请看 Regular Expressions.

Working with array-like objects

一些 JavaScript 对象, 例如 document.getElementsByTagName() 返回的 NodeList 或者函数内部可用的 arguments 对象,他们表面上看起来,外观和行为像数组,但是不共享他们所有的方法。arguments 对象提供一个 length 属性,但是不实现 forEach() 方法, 例如:

Array generics, provide a way of running Array methods against other array-like objects. Each standard array method has a corresponding method on the Array object itself; for example:

function printArguments() {
  Array.forEach(arguments, function(item) {
    console.log(item);
  });
}

These generic methods can be emulated more verbosely in older versions of JavaScript using the call method provided by JavaScript function objects:

Array.prototype.forEach.call(arguments, function(item) {
  console.log(item);
});

Array generic methods can be used on strings as well, since they provide sequential access to their characters in a similar way to arrays:

Array.forEach("a string", function(chr) {
  console.log(chr);
});

数组推导式

JavaScript 1.7 被介绍并计划在 ECMAScript 7, array comprehensions 被规范化并提供一个有用的快捷方式,用来实现如何在另一个数组的基础上构造一个新的数组。推导式可以经常被用在那些需要调用 map()filter()函数的地方,或作为一种结合这两种方式。

下面的推导式创建一个数字数组并且创建一个新的数组,数组的每个元素都是原来数值的两倍(译者注:这种形式类似于Python的列表推导式)。

var numbers = [1, 2, 3, 4];
var doubled = [i * 2 for (i of numbers)];
console.log(doubled); // logs 2,4,6,8

这跟下面的map()方法的操作是等价的。

var doubled = numbers.map(function(i){return i * 2;});

推导式也可以用来筛选满足条件表达式的元素. 下面的推导式用来筛选是2的倍数的元素:

var numbers = [1, 2, 3, 21, 22, 30];
var evens = [i for (i of numbers) if (i % 2 === 0)];
console.log(evens); // logs 2,22,30

filter() 也可以达到相同的目的:

var evens = numbers.filter(function(i){return i % 2 === 0;});

map() and filter() style operations can be combined into a single array comprehension. Here is one that filters just the even numbers, then creates an array containing their doubles:

var numbers = [1, 2, 3, 21, 22, 30];
var doubledEvens = [i * 2 for (i of numbers) if (i % 2 === 0)];
console.log(doubledEvens); // logs 4,44,60

The square brackets of an array comprehension introduce an implicit block for scoping purposes. New variables (such as i in the example) are treated as if they had been declared using let. This means that they will not be available outside of the comprehension.

The input to an array comprehension does not itself need to be an array; iterators and generators can also be used.

甚至字符串也可以用来作为输入; to achieve the filter and map actions (under Array-like objects) above:

var str = 'abcdef';
var consonantsOnlyStr = [c for (c of str) if (!(/[aeiouAEIOU]/).test(c))  ].join(''); // 'bcdf'
var interpolatedZeros = [c+'0' for (c of str) ].join(''); // 'a0b0c0d0e0f0'

Again, the input form is not preserved, so we have to use join() to revert back to a string.

类型化数组

JavaScript typed arrays 是array-like 对象,并且提供访问原始二进制数据的机制。 就像你知道的那样, Array 对象动态增长和收缩,可以有任何JavaScript值。JavaScript引擎执行优化使得这些数组访问速度快速。但是, 随着Web应用程序变得越来越强大,添加音频和视频处理等功能,可以使用 WebSockets使用原始数据, 它已经很清楚,有些时候,这将有助于JavaScript代码能够快速和容易地操纵原始二进制数据类型的数组。

缓冲区和视图:类型化的数组结构

To achieve maximum flexibility and efficiency, JavaScript typed arrays split the implementation into buffers and views. A buffer (implemented by the ArrayBuffer object) is an object representing a chunk of data; it has no format to speak of, and offers no mechanism for accessing its contents. In order to access the memory contained in a buffer, you need to use a view. A view provides a context — that is, a data type, starting offset, and number of elements — that turns the data into an actual typed array.

Typed arrays in an ArrayBuffer

ArrayBuffer

The ArrayBuffer is a data type that is used to represent a generic, fixed-length binary data buffer. You can't directly manipulate the contents of an ArrayBuffer; instead, you create a typed array view or a DataView which represents the buffer in a specific format, and use that to read and write the contents of the buffer.

Typed array views

Typed array views have self descriptive names and provide views for all the usual numeric types like Int8, Uint32, Float64 and so forth. There is one special typed array view, the Uint8ClampedArray. It clamps the values between 0 and 255. This is useful for Canvas data processing, for example.

Type Size in bytes Description Web IDL type Equivalent C type
Int8Array 1 8-bit two's complement signed integer byte int8_t
Uint8Array 1 8-bit unsigned integer octet uint8_t
Uint8ClampedArray 1 8-bit unsigned integer (clamped) octet uint8_t
Int16Array 2 16-bit two's complement signed integer short int16_t
Uint16Array 2 16-bit unsigned integer unsigned short uint16_t
Int32Array 4 32-bit two's complement signed integer long int32_t
Uint32Array 4 32-bit unsigned integer unsigned long uint32_t
Float32Array 4 32-bit IEEE floating point number unrestricted float float
Float64Array 8 64-bit IEEE floating point number unrestricted double double

Fore more information, see JavaScript typed arrays and the reference documentation for the different TypedArray objects.

文档标签和贡献者

 最后编辑者: kiyonlin,