JavaScript数组
1. 简介
在JavaScript中数组是特殊的对象。与普通对象不同的是数组有一个length属性,length属性会随着数组元素的增加和减少自动更新。
2. 创建数组
在JavaScript中有两种方式创建数组,通过数组字面值和Array()构造函数。
2.1 通过数组字面值创建数组
//创建一个空数组 var empty = []; //=>[] var primes = [2, 3, 5, 7, 11] //=>[2, 3, 5, 7, 11] //数组末尾的逗号将被忽略 var misc = [1.1, true, 'a', ] //=>[1.1, true, "a"] //数组字面值不必为常量,可以包含表达式 var base = 1024; var table = [base, base+1, base+2, base+3]; //=>[1024, 1025, 1026, 1027] //在数组字面量中省略的值将被赋值为undefined var count = [1,,3]; //=>[1, undefined × 1, 3]
2.2 通过Array()构造函数创建数组
//不传入参数调用 var a = new Array(); //=>[] //传入一个数字参数将作为数组的长度 var arr = new Array(10); //=> [undefined × 10] //传入两个以上参数或一个非数字参数,将返回以参数为元素的数组 var array = new Array(5, 4, 3, 2, 1, "testing, testing"); //=>[5, 4, 3, 2, 1, "testing, testing"]3
3. 读写数组元素
3.1 读写格式
读写数组元素只需将数组名加上方括号和索引即可,索引为一个返回非负整数的表达式。
var arr = ["array"]; //定义一个数组 var value = arr[0]; //读取数组元素值 arr[1] = 3.14; //给数组元素赋
3.2 数组索引和对象属性名的区别
数组是特殊的对象,所有的数组索引都是对象属性名,但只有小于2的32次方的非负整数的属性名才是索引。当采用一个负数或非整数作为数组索引时会将该数字转换为字符串作为对象属性名,采用一个非负整数字符串时会将其转换为数字作为数组索引。JavsScript数组不存在越界问题,当访问一个不存在的元素时会返回undefined.
var arr = []; arr[-1] = true; //创建一个名为"-1"的属性 arr["1000"] = 0 //访问数组的第1001个元素 arr[1.000]; //访问数组的第2个元素
4. 稀疏数组
4.1 当一个数组的索引不是以0开始的连续整数时,这个数组为稀疏数组。可以通过Array(), 将数组的length给一个超出其元素个数的值以及使用delete操作符获得稀疏数组。
var arr1 = new Array(5); // =>[undefined × 5] var arr2 = [1, 2]; arr2.length = 3; // =>[1, 2, undefined × 1]
4.2 稀疏数组和数组元素值为undefined区别
在数组字面值中省略值会给省略的元素undefined, 这与稀疏数组不同。稀疏数组中元素根本不存在。
5. 数组长度
5.1 每个数组有一个length属性。密集数组的length值等于元素个数,稀疏数组length值大于元素个数。
[].length // => 0: the array has no elements ['a','b','c'].length // => 3: highest index is 2, length is 3
5.2 数组length大于任何数组元素的索引值。当给数组中索引大于或等于length的元素赋值时,length会自动增加。当将数组length设置为一个小于当前元素的值时会删除索引大于等于length的元素。
a = [1,2,3,4,5]; // Start with a 5-element array. a.length = 3; // a is now [1,2,3]. a.length = 0; // Delete all elements. a is []. a.length = 5; // Length is 5, but no elements, like new Array(5)
5.3 在ECMAScript5中可设置数组的length为只读属性,这时将不能通过设置length删除元素。
a = [1,2,3]; // Start with a 3-element array. Object.defineProperty(a, "length", // Make the length property {writable: false}); // readonly. a.length = 0; // a is unchanged.
6.增加和删除数组元素
6.1 增加数组元素
6.1.1 通过数组字面值增加数组元素
var arr = []; // [] arr[0] = 0; // [0]
6.1.2 通过push()和unshift()方法增加数组元素
push()在数组末尾增加一个元素,unshift()在数组开始增加一个元素。
a = []; // Start with an empty array a.push("zero") // Add a value at the end. a = ["zero"] a.push("one", "two") // Add two more values. a = ["zero", "one", "two"]
6.2 删除数组元素
6.2.1 使用delete 操作符删除数组元素。不会改变数组length也不会移动其他元素,数组变为稀疏数组。
var arr = [1, 2, 3]; // =>[1, 2, 3] delete arr[1]; // => [1, undefined × 1, 3] 1 in arr; // false arr.length; // 3
6.2.2 使用pop()和shift()删除数组元素。pop()删除最后一个元素,shift()删除第一个元素,其他元素向前移动。pop()和shift()均会改变数组length.
var arr = [1, 2, 3]; arr.pop(); // => [1, 2] arr.length; //=> 2 arr.shift(); //=> [2] arr.length; // => 1
6.2.3 设置数组length为小于当前元素个数的值
var arr = [1, 2, 3, 4, 5]; // => [1, 2, 3, 4, 5] arr.length = 3; // => [1, 2, 3]
7. 遍历数组
7.1 当数组为密集数组且数组元素都有效时用for循环遍历:
var arr = [1,2,3]; for (var i = 0; i < arr.length; i++) { ; }
7.2 过滤值为null, undefined和不存在的元素
for (var i = 0; i < arr.length; i++) { if (!arr[i]) continue; ; }
7.3 过滤undefined的元素和不存在的元素
for (var i = 0; i < arr.length; i++) { if (arr[i] === undefined) continue; ; }
7.4 过滤不存在的元素
for (var i = 0; i < arr.lenth; i++) { if (!(i in arr)) continue; ; }
7.5 使用for/in循环遍历数组。遍历顺序与浏览器具体实现有关。
//遍历可枚举属性,包括数组元素索引 for(var index in sparseArray) { var value = sparseArray[index]; // Now do something with index and value } for(var i in a) { if (!a.hasOwnProperty(i)) continue; // Skip inherited properties // loop body here } for(var i in a) { // Skip i if it is not a non-negative integer if (String(Math.floor(Math.abs(Number(i)))) !== i) continue; }
7.6 使用ECMAScript5中定义的forEach方法遍历
var data = [1,2,3,4,5]; // This is the array we want to iterate var sumOfSquares = 0; // We want to compute the sum of the squares of data data.forEach(function(x) { // Pass each element of data to this function sumOfSquares += x*x; // add up the squares }); sumOfSquares // =>55 : 1+4+9+16+25
8. 数组方法
ECMAScript 在Array.prototype中定义了一系列有用的方法
8.1 join()
将数组元素连接为一个字符串,不传参数时以逗号间隔,传入参数时已传入的字符串作为分隔符。
var arr = [1, 2, 3]; arr.join(); // => "1,2,3" arr.join("-"); // => "1-2-3" arr.join(""); // => "123" var arr2 = new Array(10); arr2.join("-"); // => "---------"
8.2 reverse()
将数组元素逆序,返回重新排序后的数组,不会创建新数组。
var arr = [1, 2, 3]; arr.reverse(); // [3, 2, 1]
8.3 sort()
将数组元素排序,然后返回数组。不传参数时以字母顺序排序,值为undefined的元素排在末尾。
var a = new Array("banana", "cherry", "apple"); a.sort(); var s = a.join(", "); // s == "apple, banana, cherry"
需要以其他顺序排序时可传入一个比较函数。比较函数有两个参数,a和b.当需要a出现在b前面时返回小于0的数字,相反则返回大于0的数字。
a.sort(function(a,b) { return a-b; });
8.4 concat()
在数组上调用concat()时会创建并返回一个包含调用数组和参数的新数组。如果参数为数组则会将数组元素包含在新数组中,参数中有多维数组时只会包含第一层数组元素。concat()不会改变调用的数组。
var a = [1,2,3]; a.concat(4, 5) // Returns [1,2,3,4,5] a.concat([4,5]); // Returns [1,2,3,4,5] a.concat([4,5],[6,7]) // Returns [1,2,3,4,5,6,7] a.concat(4, [5,[6,7]]) // Returns [1,2,3,4,5,[6,7]]
8.5 slice()
返回数组的一个子数组。接收两个参数,第一个参数表示开始元素的索引,第二个参数表示结束元素的索引。返回的子数组包含开始元素不包含结束元素。当参数为负数时表示已数组末尾计数。slice()不会改变调用的数组。
var a = [1,2,3,4,5]; a.slice(0,3); // Returns [1,2,3] a.slice(3); // Returns [4,5] a.slice(1,-1); // Returns [2,3,4] a.slice(-3,-2); // Returns [3]
8.6 splice()
splice()可以删除数组元素、增加数组元素或同时删除和增加数组元素。第一个参数指定元素位置,第二个参数指定删除元素个数。当传入大于两个参数时会将其他参数作为数组元素插入到数组中。和concat()不同splice()不会将数组的元素单独插入而是插入数组本身。
var a = [1,2,3,4,5,6,7,8]; a.splice(4); // Returns [5,6,7,8]; a is [1,2,3,4] a.splice(1,2); // Returns [2,3]; a is [1,4] a.splice(1,1); // Returns [4]; a is [1]
8.7 pop() 和 push()
8.7.1 pop()
删除数组最后一个元素,减小lenght,返回删除的值。pop()不会创建新数组而是修改原来的数组。
8.7.2 push()
向数组末尾增加一个元素,增加length,返回增加后的length.
8.7.3 利用pop() 和 push() 实现以下先入后出栈
var stack = []; // stack: [] stack.push(1,2); // stack: [1,2] Returns 2 stack.pop(); // stack: [1] Returns 2 stack.push(3); // stack: [1,3] Returns 2 stack.pop(); // stack: [1] Returns 3 stack.push([4,5]); // stack: [1,[4,5]] Returns 2 stack.pop() // stack: [1] Returns [4,5] stack.pop(); // stack: [] Returns 1
8.8 shift() 和unshift()
8.8.1 shift() 在数组开始删除一个元素,减小length,返回删除元素,将其他元素向前移动。
var arr = [0,1,2,3,4,5,6]; arr.shift(); // Return: 0, arr:[1, 2, 3, 4, 5, 6]
8.8.2 unshift()在数组开始插入一个元素,增加length,返回length,将其他元素向后移动。当传入多个参数调用unshift()时,所有参数在一次插入数组。
var a = []; // a:[] a.unshift(1); // a:[1] Returns: 1 a.unshift(22); // a:[22,1] Returns: 2 a.shift(); // a:[1] Returns: 22 a.unshift(3,[4,5]); // a:[3,[4,5],1] Returns: 3
8.9 toString()和toLocaleString()
和对象一样,每个数组都有toString方法。toString()首先将每个数组元素转换为字符串然后将它们用逗号隔开连起来,最后作为一个字符串返回(和不传参数调用join()返回值相同)。toLocaleString()是本地版本的toString().
[1,2,3].toString(); // Returns "1,2,3" ["a", "b", "c"].toString(); // Returns "a,b,c" [1,[2,"a"]].toString(); // Returns "1,2,a"
9 ECMAScript 5 数组方法
ECMAScript 5定义了9个新方法用于迭代、映射、过滤、测试, 减少和搜索数组。这些方法大多接收一个函数作为第一个参数,对所有(部分)的元素调用这个函数。这个函数一般有3个参数,第一个是数组元素的值,第二个是数组元素的索引,第三个是数组本身。这些方法还接收第二个可选的参数作为函数调用时的this值。ECMAScript 5数组方法都不会修改调用方法的数组。
9.1 forEach()
对数组的每个元素调用传入的函数(对于稀疏数组,不存在的元素不会调用)。
var data = [1,2,3,4,5]; // An array to sum // Compute the sum of the array elements var sum = 0; // Start at 0 data.forEach(function(value) { sum += value; }); // Add each value to sum sum // => 15 // Now increment each array element data.forEach(function(v, i, a) { a[i] = v + 1; }); data // => [2,3,4,5,6]exception,
forEach()没有提供一个方法来停止迭代(不能像在循环中那样使用break语句)。如果要提前停止迭代需要抛出一个exception并且将forEach()的调用放在try block中。
function foreach(a,f,t) { try { a.forEach(f,t); } catch(e) { if (e === foreach.break) return; else throw e; } } foreach.break = new Error("StopIteration");
9.2 map()
对数组的每个元素调用传入的函数,返回一个对应的函数。传入的函数应有一个返回值。调用map()的数组为稀疏数组时返回的数组也为稀疏数组(有相同的长度和缺少元素)。
arr.map(function(v, i, a) {return a+" "+i+" "+v}); // Returns: ["1,2,3 0 1", "1,2,3 1 2", "1,2,3 2 3"]
9.3 filter()
filter()返回调用此方法的数组的一个子数组。传入filter的函数应返回一个布尔值,当返回true时元素位于返回的数组中。
var arr = [1, 2, 3, 4, 5]; arr.filter(function(v) { return v > 3}); // Returns: [4, 5]
filter会忽略不存在的元素,对稀疏数组调用filter()时返回的是一个密集数组。
// 删除稀疏数组的间隔,返回一个密集数组 var arr2 = arr1.filter(function() {return true});
9.4 every()和some()
every()对数组的每个元素调用传入的函数,如果都返回true则返回true.some()对数组的每个元素调用传入的函数,只要有一个元素返回true则返回true.every()和some()会在满足判断条件时停止迭代数组。
对空数组调用every()时返回true,调用some()返回false.
var arr = [1, 2, 3, 4, 5]; arr.every(function(x) { return x < 10;}); // Returns: true arr.every(function(x) { return x % 2 === 0;}); // Returns: false arr.some(function(x) { return x % 2 === 0;}); // Returns: true arr.some(function(x) { return x > 10;}); // Returns: false
9.5 reduce(), reduceRight()
reduce()将调用其的数组元素产生一个值返回。reduce()接收的第一个参数为一个函数,第二个可选的参数为默认值。reduce()不接收this参数,如需绑定到某个对象执行传入函数可采用Function.bind()实现。reduce()与其他数组方法不同,传入reduce()的函数第一个参数为上一次计算值(第一次调用为默认值,如无默认值则为数组第一个元素值),第二个为当前元素值。在空数组上不传入默认值调用reduce()时会抛出一个TypeError,传入一个默认值或者数组只有一个元素时,返回这个值。reduceRight()的计算方向和reduce()相反。
var a = [1,2,3,4,5] var sum = a.reduce(function(x,y) { return x+y }, 0); // Sum of values var product = a.reduce(function(x,y) { return x*y }, 1); // Product of val
9.6 indexOf() 和 lastIndexOf()
indexOf()返回特定值在数组中的索引,当数组中不存在这个值时返回-1。indexOf()从数组的第一个元素开始搜索,lastIndexOf()从数组的最后一个元素开始搜索。indexOf()接收第二个可选的参数指定开始搜索的位置,传入负数时从数组末尾计数。
var arr = [0, 1, 2, 1, 0]; arr.indexOf(1); // 1 arr.lastIndexOf(1) // 3
利用indexOf()找到数组中所有等于某个值的元素。
// Find all occurrences of a value x in an array a and return an array // of matching indexes function findall(a, x) { var results = [], // The array of indexes we'll return len = a.length, // The length of the array to be searched pos = 0; // The position to search from while(pos < len) { // While more elements to search... pos = a.indexOf(x, pos); // Search if (pos === -1) break; // If nothing found, we're done. results.push(pos); // Otherwise, store index in array pos = pos + 1; // And start next search at next element } return results; // Return array of indexes }
字符串中的indexOf()和lastIndexOf()与数组中的相同。
10. 数组类型
数组是拥有一些特殊行为的对象。在ECMAScript 5中区分数组与一般对象可采用Array.isArray().在ECMAScript 3中区分数组与一般对象则不是很容易。
10. 1 不能使用typeof 操作符,typeof 操作符对数组返回的是 "object"
var arr = []; typeof arr; // "object"
10.2 instanceof 操作符可以区分数组和对象,但在有多个窗口时不一定有效。因为每个窗口都有自己的运行环境以及自己的全局变量。一个窗口的值不一定是另一个窗口函数的实例。
[] instanceof Array // => true ({}) instanceof Array // => false
10.3 可通过class属性区分,对于数组class属性是"Array".
//定义一个通用的区分数组与对象的方法 var isArray = Function.isArray || function(o) { return typeof o === "object" && Object.prototype.toString.call(o) === "[object, Array]"; }
11. 类数组对象
11.1 数组拥有的特性
(1)有一个自动更新的length属性;
(2)设置length为一个更小的值可以删除数组元素;
(3)从Array.prototype继承了一系列有用的方法;
(4)数组的class属性是"Array".
11.2 通过给普通对象设置length属性和采用数字最为属性名可以将其转换为类数组对象。
var a = {}; // Start with a regular empty object // Add properties to make it "array-like" var i = 0; while(i < 10) { a[i] = i * i; i++; } a.length = i; // Now iterate through it as if it were a real array var total = 0; for(var j = 0; j < a.length; j++) total += a[j];
11.3 ECMAScript 5中定义的所有方法都可在类数组对象上调用,ECMAScript 3中除了toString() 和 toLocaleString()的其他方法也可在类数组对象上调用。
浙公网安备 33010602011771号