说明
本系列博客的第一篇已经说明了,要求阅读者需要具有其它语言的编程基础,所以关于组数的基础部分本篇博客将不再赘述,主要讲js中数组的特性。
创建数组
数组的创建主要有两种方法,一种是数组直接量,还有一种是new Array()的方式。其中这两种方式都和java中创建数组的方式类似。
1 var a = []; //创建一个没有元素的数组,并用a引用它。 2 var b = [1,,2] //创建一个只有两个元素,但是数组length值为3的数组。 3 var c = new Array(5); //创建一个没有元素,但是数组length值为5的数组。 4 var d = new Array(5, "hello", true); //创建一个含有三个元素的数组,其中第一个元素值为数值5,第二个元素值为字符串"hello",第三个元素值为布尔型值true。
注意上面出现的虽然数组中没有元素,但是数组的length依然大于零的情况,这讲在下文进行详细介绍。
数组元素的读写
在js中你始终需要记住没有数组、函数等这种类型,它们都是对象类型。在本系列的博客的第一篇就讲过,js中数据类型分六种(数值、字符串、布尔、null、undefined、对象)。所以说数组也是对象类型的一种。
和其它大多数语言一样,js中的数组元素的方式支持下标访问形式,不同的是js不仅是动态类型的语言,它的数组还是对象类型的一种,这就注定js在操作数组时不会报下标越界、空指针异常等错误。如果访问的下标存在,则js会访问对于的元素,如果不存在,则会创建该下标对应的元素(写)或者返回undefined(读)。
1 var a = [1]; //创建一个含有一个元素的数组 2 a[0] //1:访问该元素 3 a[1] //undefined:下标为1的元素不存在 4 a[2]="hello" //创建该下标对应的元素 5 a[2] //"hello":访问下标为2的元素 6 a[-1.23]=true //创建属性名为"-1.23"属性值为true的属性。 7 a[1.000]="hi" //创建下标为1的元素,相当于a[1]="hi"
仔细看上面的代码,我们来总结一下js中数组的一些特点。首先和其它常用的编程语言一样,数组下标从0开始。数组的元素可以不必连续,比如这里先有一个下标为0的元素,接下来创建了一个下标为2的元素,不必保证下标为1的元素必须存在。数组中元素的类型可以五花八门,a[0]为数值,a[2]为字符串,不必保持统一。当一个给出的下标无法正确转换为一个正整数时(上面的a[-1.23],js将还原数组的本质(对象),把a当成一个普通对象处理,所以会在a中创建一个属性。
稀疏数组
上面谈到过在js中会出现元素为空,但是length大于零的情况。这就是js中所谓的稀疏数组。在js中数组对象的length会大于等于元素个数,当等于元素个数时称之为稠密数组,当大于元素个数时称之为稀疏数组。稀疏数组中某个元素不存在并不是指这个下标对应的元素的值为undefined,而是指这个下标对应的元素是空的,不存在这个元素。下图是在chrome中实验的案例。
上面我们的出一个结论"数组对象的length会大于等于它元素的个数"。既然length是一个属性值,那如果我们直接对它进行修改会怎样了?
除此之外,数组作为一个普通对象,我们还能用本系列第四篇博客中的对象的配置方法对其进行配置,比如我们将length属性配置为不可写,那么意味着我们固定了这个数组元素的最大个数。
数组中常用的方法
这部分内容比较好懂,主要是数组对象中一些方法的调用。基本上都是用到的时候再查API,当查久了,积累了就变成自己的了。具体请参考这个网页。
ECMAScript5中数组方法
forEach
在开始介绍这些方法之前先对这些方法的用法做一个介绍,这些方法的第一个参数一般接收一个函数(为了表示方便,下文统称这个函数为"参数函数"),如果有第二个参数,那么当参数函数被调用时,它的this值就是第二个参数。其中参数函数一般能支持三个参数,分别表示:数组元素、元素索引和数组本身。通常人们只使用写一个参数,而省略后面两个参数(见map函数的例子)。这么说了一大堆你可能已经迷惑了,没关系,我们下面先来一个模板来具体化一下。
1 //forEach为Array中的一个方法,用于遍历每一个可枚举元素(包括继承来的)。 2 var data1=[1,2,3]; 3 data1['name']='data1'; 4 var data2=['a', 'b', 'c']; 5 data2['name']='data2'; 6 data1.forEach(function(value, index, arr){ 7 console.log("The value of " + index + " element in " + arr.name + " is " + value); 8 }); 9 data1.forEach(function(value, index, arr){ 10 console.log("The value of " + index + " element in " + arr.name + " is " + value); 11 }, data2); 12 data1.forEach(function(value, index, arr){ 13 console.log("The value of " + index + " element in " + this.name + " is " + value); 14 }, data2);
在上面的例子中,参数函数作为第一个参数是一个匿名函数,第二个(可选)参数为data2,其中参数函数的三个参数分别是:value、index和arr。对于数组中的每一个元素,forEach都会调用一次参数函数。上面的代码在chrome中执行结果如下:
map
map和forEach函数差不多,只是map有返回值,它返回一个数组。注意,这里map不修改原数组,而是返回一个新的数组,新数组和原数组一样具有相同的长度,如果是稀松数组还具有相同的缺失元素。
1 var a=[1, 2, 3]; 2 var b=a.map(function(x){ return x*x;}) //b是[1, 4, 9]
filter
该函数用于过滤数组中的元素。对于每个元素,只有当参数函数的返回值为true时,当前元素才放入新的数组中,最后将新数组作为filter方法的返回值。
1 var a=[5, 4, 3, 2, 1]; 2 var small = a.filter(function(x){ return x<3;}); //[1,2] 3 var odd = a.filter(function(x){ return x%2;}); //[1,3,5]
由于和forEach等方法一样,filter会跳过缺失的元素,所以利用这个特性可以用filter方法来实现稀疏数组向稠密数组的转化
1 //稀疏数组转稠密数组 2 var dense = sparse.filter(function(){ return true;}); 3 4 //稀疏数组转稠密数组并去掉值为undefined和null的元素 5 var dense2 = sparse.filter(function(x){ return x !== undefined && x !== null;});
every和some
这两个方法类似于逻辑代数中的任意Ɐ和存在ⱻ。和上面的方法一样,针对数组中的每一个元素,这两个方法都会调用它的参数函数。对于every而言只有参数函数全部返回true,every方法才返回true。而some则是在调用参数函数的过程中只有有一次返回true,则some方法就返回true。
reduce和reduceRight
这两个方法所接受的参数和上面那些方法稍有区别,它俩的第一个参数依然需要一个函数(这里继续简称"参数函数"),其中参数函数有两个参数。它俩的第二个参数(可选)是一个初始值。这两个方法的主要作用是利用某种方法(参数函数)将整个数组中的元素合并为一个元素并返回。也许说了这么多你还是有点模糊,看一下下面的例子你就应该比较清楚了:
1 var a=[1, 2, 3, 4, 5]; 2 3 var sum = a.reduce(function(x, y){ return x+y;}, 0); //求和 4 //首先初始值为0,所以第一次调用参数函数传入(0,1),返回1 5 //第二次调用参数函数传入上一次的返回值1和数组中的第二个元素2,即(1,2),返回3 6 //第三次调用参数函数传入(3,3) 7 //接下来依次是:(6,4)、(10,5)-->最后返回15 8 9 var max = a.reduce(function(x,y){ return (x>y)?x:y;}); //求最大值
reduceRight和reduce函数一样,只是参数传入的顺序从数组的最大索引处开始,比如下面这个例子:
1 var a=[2, 3, 4] 2 //计算2^(3^4) 3 var result = a.reduceRight(function(x, y){ return Math.pow(y,x);});
indexOf和lastIndexOf
这两个方法的做法和上面哪些方法完全不同,它俩用法很简单,就是在数组中查找某个元素第一次出现的下标。它们支持两个参数,第一个参数是要搜索的值,第二个参数为起始下标(如果省略indexOf从头开始,lastIndexOf从末尾开始),其中第二个参数可以是负数,表示从末尾开始的偏移量。下面是在chrome中简单的对这两个方法的使用。