本文编写于 170 天前,最后修改于 170 天前,其中某些信息可能已经过时。

说明

  本系列博客的第一篇已经说明了,要求阅读者需要具有其它语言的编程基础,所以关于组数的基础部分本篇博客将不再赘述,主要讲js中数组的特性。

创建数组

  数组的创建主要有两种方法,一种是数组直接量,还有一种是new Array()的方式。其中这两种方式都和java中创建数组的方式类似。

var a = [];    //创建一个没有元素的数组,并用a引用它。
var b = [1,,2]    //创建一个只有两个元素,但是数组length值为3的数组。
var c = new Array(5);    //创建一个没有元素,但是数组length值为5的数组。
var d = new Array(5, "hello", true);    //创建一个含有三个元素的数组,其中第一个元素值为数值5,第二个元素值为字符串"hello",第三个元素值为布尔型值true。

  注意上面出现的虽然数组中没有元素,但是数组的length依然大于零的情况,这讲在下文进行详细介绍。

链接:

JavaScript 基础入门教程(一) http://blog.zh66.club/index.php/archives/81/
JavaScript 基础入门教程(二) http://blog.zh66.club/index.php/archives/83/
JavaScript 基础入门教程(三) http://blog.zh66.club/index.php/archives/87/
JavaScript 基础入门教程(四) http://blog.zh66.club/index.php/archives/92/

数组元素的读写

  在js中你始终需要记住没有数组、函数等这种类型,它们都是对象类型。在本系列的博客的第一篇就讲过,js中数据类型分六种(数值、字符串、布尔、null、undefined、对象)。所以说数组也是对象类型的一种。

  和其它大多数语言一样,js中的数组元素的方式支持下标访问形式,不同的是js不仅是动态类型的语言,它的数组还是对象类型的一种,这就注定js在操作数组时不会报下标越界、空指针异常等错误。如果访问的下标存在,则js会访问对于的元素,如果不存在,则会创建该下标对应的元素(写)或者返回undefined(读)。

var a = [1];    //创建一个含有一个元素的数组
a[0]    //1:访问该元素
a[1]    //undefined:下标为1的元素不存在
a[2]="hello"    //创建该下标对应的元素
a[2]    //"hello":访问下标为2的元素
a[-1.23]=true    //创建属性名为"-1.23"属性值为true的属性。
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函数的例子)。这么说了一大堆你可能已经迷惑了,没关系,我们下面先来一个模板来具体化一下。

//forEach为Array中的一个方法,用于遍历每一个可枚举元素(包括继承来的)。
var data1=[1,2,3];
data1['name']='data1';
var data2=['a', 'b', 'c'];
data2['name']='data2';
data1.forEach(function(value, index, arr){
    console.log("The value of " + index + " element in " + arr.name + " is " + value);
});
data1.forEach(function(value, index, arr){
    console.log("The value of " + index + " element in " + arr.name + " is " + value);
}, data2);
data1.forEach(function(value, index, arr){
    console.log("The value of " + index + " element in " + this.name + " is " + value);
}, 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
  这两个方法所接受的参数和上面那些方法稍有区别,它俩的第一个参数依然需要一个函数(这里继续简称"参数函数"),其中参数函数有两个参数。它俩的第二个参数(可选)是一个初始值。这两个方法的主要作用是利用某种方法(参数函数)将整个数组中的元素合并为一个元素并返回。也许说了这么多你还是有点模糊,看一下下面的例子你就应该比较清楚了:

var a=[1, 2, 3, 4, 5];

var sum = a.reduce(function(x, y){ return x+y;}, 0);    //求和
//首先初始值为0,所以第一次调用参数函数传入(0,1),返回1
//第二次调用参数函数传入上一次的返回值1和数组中的第二个元素2,即(1,2),返回3
//第三次调用参数函数传入(3,3)
//接下来依次是:(6,4)、(10,5)-->最后返回15

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中简单的对这两个方法的使用。

链接:
JavaScript 基础入门教程(一) http://blog.zh66.club/index.php/archives/81/
JavaScript 基础入门教程(二) http://blog.zh66.club/index.php/archives/83/
JavaScript 基础入门教程(三) http://blog.zh66.club/index.php/archives/87/
JavaScript 基础入门教程(四) http://blog.zh66.club/index.php/archives/92/