JavaScript数组的索引是基于零的32位数值:第一个元素的索引是0,最大可能的索引位4 294 967 294(2^32 - 2,数组最大能容纳4 294 967 294个元素

一、创建数组

如果省略数组直接量中的某个值,省略的元素将被赋予undefined值。

数组直接量的语法允许有可选的结尾的逗号,故[,,]只有两个元素而非三个。

二、数组元素的读和写

数组是对象的特殊形式,使用方括号访问数组元素就想用方括号访问对象的属性一样。JavaScript将指定的数字索引值转换为字符串————索引值1变为"1"————然后将其作为属性名来使用。

可以使用负数或非整数来索引数组。这种情况下,数值转换为字符串,字符串作为属性名来用。既然名字不是非负整数,它就只能当做常规的对象属性,而非数组的索引。同样,如果使用非负整数的字符串,它就当做数组索引,而非对象属性。当使用的一个浮点数和一个整数相等时情况也是一样的:

a[-1.23] = true;   //这将创建一个名为"-1.23"的属性
a["1000"] = 0;     //这是数组的第1001个元素
a[1.000]           //和a[1]相等

三、稀疏数组

稀疏数组就是包含从0开始的不连续索引的数组。通常,数组的length属性值代表数组中元素的个数,如果数组是稀疏的,length属性的值大于数组的元素个数。创建稀疏数组:

new Array(5);       //数组没有元素,但a.length是5
a = [];             //创建一个空数组,length = 0
a[1000] = 1;        //赋值添加一个元素,这时a.length = 1001

当省略数组直接量中的值时(使用连续的逗号,比如[1,,3]),这时所得到的数组也是稀疏数组,省略掉的值时不存在的。

var a = [1,,undefined,2];
1 in a;     //false
2 in a;     //true

对一个数组元素使用delete不会修改数组的length属性,也不会将元素从高索引处移下来填充已删除属性留下的空白。如果从数组中删除一个元素,它就变成稀疏数组。

四、数组长度

数组有两个特殊的行为:
1、如果为一个数组元素赋值,它的索引i大于或等于现有数组的长度时,length属性的值将设置为i + 1;
2、设置length属性为一个小于当前长度的非负整数n时,当前数组那些索引值大于或等于n的元素将从中删除。

五、数组方法

1、join()

将数组中的所有元素转化为字符串并连接在一起,返回最后生成的字符串

var a = [1,2,3];
a.join("-");   //"1-2-3"

2、reverse()

将数组中的元素颠倒顺序,返回逆序的数组

var a = [1,2,3];
a.reverse();   //[3, 2, 1]

3、sort()

将数组中的元素排序并返回排序后的数组。当不带参数调用sort()时,数组元素以字母表顺序排序,如果数组包含undefined元素,它们会被排到数组的尾部。

可以给sort()传入一个比较函数

· 用数值大小进行排序:

var a = [33,44,2,5,1];
a.sort(function(a,b){return a - b});  //[1, 2, 5, 33, 44]

· 区分大小写排序

var a = ['ant','Bug','cat','Dog'];
a.sort();           //区分大小写排序["Bug", "Dog", "ant", "cat"]
a.sort(function(a,b){
	var c = a.toLowerCase();
	var d = b.toLowerCase();
	if(c < d) {
		return -1;
	};
	if(c > d) {
		return 1;
	};
	return 0;
});                //不区分大小写排序["ant", "Bug", "cat", "Dog"]

· 根据对象属性排序

var a = [
	{business: "保险", week: 10, year: 200},
	{business: "基金", week: 12, year: 2020},
	{business: "借呗", week: 57, year: 1111}
];
function compare(name) {
	return function(object1, object2) {
		var value1 = object1[name];
		var value2 = object2[name];
		if(value1 < value2) {
			return -1;
		};
		if(value1 > value2) {
			return 1;
		};
		return 0;
	}
}
a.sort(compare("year"));

4、concat()

该方法创建并返回一个新数组,它的元素包括调用concat()的原始数组的元素和concat()的每个参数,如果这些参数中的任何一个自身是数组,则连接的是数组的元素。

var a = [1,2,3];
a.concat(4,5);         //[1, 2, 3, 4, 5]
a.concat([4,5]);       //[1, 2, 3, 4, 5]
a.concat([4,[5,6]]);   //[1,2,3,4,[5,6]]

5、slice()

该方法指定数组的一个片段或子数组。它的两个参数分别指定了片段的开始和结束的位置。返回的数组包含第一个参数指定的位置和所有到但不含第二个参数指定的位置之间的所有数组元素。如果只指定一个参数,返回的数组将包含从开始位置到数组结尾的所有元素。如果参数中出现负数,它表示相对于数组中最后一个元素的位置,如-1指定最后一个元素,-3指定倒数第三个元素。

slice()不会修改调用的数组。

var a = [1,2,3,4,5];
a.slice(1,3);     //[2, 3]
a.slice(2);       //[3, 4, 5]
a.slice(1,-1);    //[2, 3, 4]

6、splice()

该方法是在数组中插入或删除元素的通用方法,splice()会修改调用的数组,返回一个由删除元素组成的数组,如果没有删除元素就返回一个空数组。

第一个参数指定了插入和(或)删除的位置,第二个参数指定了应该从数组中删除的元素的个数,如果省略第二个参数,从起点开始到数组结尾的所有元素都将被删除。紧随其后的任意个参数指定了需要插入到数组中的元素,从第一个参数指定的位置开始插入。

var a = [1,2,3,4,5,6,7];
a.splice(4);   //返回[5, 6, 7],a是[1,2,3,4]
a.splice(1,2); //返回[2,3],a是[1, 4]
a.splice(1,1,6,5);  //返回[4],a是[1,6,5]

7、push()和unshift()

后增和前增

会修改并替换原始数组,返回新数组的长度

8、pop()和shift()

后删和前删

会修改并替换原数组,返回被删除的值。

9、toString()

针对数组,该方法将其每个元素转化为字符串,并且输出用逗号分隔的字符串列表。
注意:输出不包括方括号或其他任何形式的包裹数组值的分隔符。

[1,[2,3],[4,[5,6]]].toString();   //"1,2,3,4,5,6"

六、ES5中的数组方法

大多数方法的第一个参数接收一个函数,并且对数组的每一个元素(或某些元素)调用一次该函数,如果是稀疏数组,对不存在的元素不调用传递的函数。在大多数情况下,调用提供的函数使用三个参数:数组元素、元素的索引和数组本身。通常,只需要第一个参数值,可以忽略后两个参数。

大多ES5的数组方法的第一个参数是一个函数,第二个参数是可选的,如果有,则调用的函数被看作是第二个参数的方法,也就是说,在调用函数时传递进去的第二个参数作为它的this关键字的值来使用。

1、forEach()

var arr = [1,2,3];
arr.forEach(function (v, i, a) {a[i] = v + 1;})
console.log(arr);    //[2, 3, 4]

注意:forEach()无法在所有元素都传递给调用的函数之前终止遍历,也就是说,没有像for循环中使用的相应的break语句。如果要提前终止,必须把forEach()放在一个try块中,并能抛出一个异常。

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");

 

2、map()

map()方法将调用的数组的每个元素传递给指定的函数,并返回一个数组。它包含该函数的返回值。所以,传递给map()的函数应该有返回值。

 

 

 

注意:1)map()返回的是新数组,它不修改调用的数组,如果是稀疏数组,返回的也是相同方式的稀疏数组:它具有相同的长度,相同的缺失元素。

 

 

            2)map不会对空数组进行检测

3、filter()

filter()方法返回的数组元素是调用的数组的一个子集。传递的函数是用来逻辑判定的:该函数返回true或false。如果返回值是true或为能转化为true的值,那么传递给判定函数的元素就是这个子集的值,它就被添加到作为一个返回值的数组中。

var a = [1,2,3,4,5,6];
var small = a.filter(function(value) {return value < 4;});  //[1, 2, 3]

filter()会跳过稀疏数组中缺少的元素,它的返回数组总是稠密的,因此,可以这样压缩稀疏数组的空缺:

var dense = a.filter(function() {return true};);

压缩空缺并删除undefined和null元素,可以这样:

a = a.filter(function(x) {return x !== undefined && x != null;});

4、every()和some()

这两种方法是数组的逻辑判定:它们对数组元素应用指定的函数进行判定,返回true或false。

every():当且仅当这对数组中的所有元素调用判定函数都返回true,它才返回true。
some():当数组中至少有一个元素调用判定函数返回true,它就返回true。

var a = [1,2,3,4,5];
a.every(function(x) {return x < 10;});      //true
a.some(function(x) {return x % 2 === 0;});  //true

5、reduce()和reduceRight()

使用指定的函数将数组元素进行组合,生成单个值。

reduce()需要两个参数,一个是执行化简操作的函数,第二个(可选)参数是一个传递给函数的初始值,当不指定第二个参数时,它将使用数组的第一个元素作为其初始值。

reduce()使用的函数与forEach()、map()使用的函数不同,数组元素、元素的索引和数组本身将作为第2~4个参数传递给函数,第一个参数是到目前为止的化简操作累积的结果。第一次调用函数时,第一个参数是一个初始值,它就是传递给reduce()的第二个参数,在接下来的调用中,这个值就是上一次化简函数的返回值。

var a = [1,2,3,4,5];
var sum = a.reduce(function(x, y) {return x + y;});  //求和 15

reduceRight()和reduce()工作原理一样,不同的是它按照数组索引从高到低的顺序处理数组。

var a = [2,3,4];
var b = a.reduceRight(function(x,y) {return Math.pow(y,x);});  //计算2^(3^4)

6、indexOf()和lastIndexOf()

第一个参数是需要搜索的值,第二个参数是可选的:它指定数组中的一个索引,从那里开始搜索。第二个参数也可以是负值,代表相对数组末尾的偏移量。

7、find()

find() 方法返回通过测试(函数内判断)的数组的第一个元素的值。

array.find(function(value, index, arr),thisValue)
value:必须,代表当前元素,其他四个参数都是可选,index代表当前索引值,arr代表当前的数组,thisValue代表传递给函数的值,一般用this值,如果这个参数为空,undefined会传递给this值

find() 方法为数组中的每个元素都调用一次函数执行:

  • 当数组中的元素在测试条件时返回 true 时, find() 返回符合条件的元素,之后的值不会再调用执行函数。
  • 如果没有符合条件的元素返回 undefined

注意: find() 对于空数组,函数是不会执行的。

注意: find() 并没有改变数组的原始值。

var arr = [1,2,3,4,5,6,7];
 var ar = arr.find(function(elem){
     return elem>5;
 });
 console.log(ar);//6
 console.log(arr);//[1,2,3,4,5,6,7]

七、数组类型

ES5中,可以用Array.isArray()函数来判断是否是数组。

Array.isArray([1,2,3]);   //true

使用instanceof的问题是在web浏览器中可能有多个窗口或窗体(frame)存在。对于一个网页嵌入多个iframe的时候,iframe1与iframe2属于不同的window对象,所以此时用instanceof判断constructor的方法失效,既然window的地址不同,那么即使相同类型也无法区分,虽然构造函数的代码一致,却处在两个window中。