最近在读《JavaScript 高级程序设计(第三版)》这本书,在这里做一下笔记,方便日后查阅。
5.2 Array类型
创建数组的两种方式。
第一种是使用Array
构造函数,如下面的代码所示。
var color = new Array();
复制代码
如果预先知道数组要保存的项目数量,也可以给构造函数传递该数量,而该数量会自动变成length
属性的值。例如,下面的代码将创建length
值为20的数组。
var colors = new Array(20);
复制代码
也可以向Array
构造函数传递数组中应该包含的项。以下代码创建了一个包含3个字符串的数组;
var colors = new Array("red","blue","green");
复制代码
当然,给构造函数传递一个值也可以创建数组。但这时候问题就会复杂一些,因为如果传递的是数值。则会按照该数值创建包含给定项数的数组;而如果传递的是其他类型的参数,则会创建包含那个值的只有一项的数组。下面就两个例子:
var colors = new Array(3); // 创建一包含3项的数组
var names = new Array("Greg"); // 创建一个包含1项,即字符串"greg"的数组
复制代码
另外,在使用Array
构造函数时也可以省略new操作符。如下面的例子所示,省略new操作符结果相同:
var colors = Array(3);
var names = Array("grey");
复制代码
第二种基本方式是使用数组字面量表示法。
数组字面量由一对包含数组项的方括号表示,多个数组项之间以逗号隔开,如下所示:
var colors = ["red","blue","green"]; // 创建一个包含三个字符串的数组
var names = []; // 创建一个空数组
var values = [1,2,]; // 不要这样!这样会创建一个包含2或3项的数组
var options = [,,,,,]; // 不要这样!这样会创建一个包含5或6项的数组
复制代码
读取和设置数组
在读取和设置数组的值时,要使用方括号并提供相应值的基于0的数字索引,如下所示:
var colors = ["red","blue","green"]; // 定义一个字符串数组
alert(colors[0]); // 显示第一项
colors[2] = "black" // 修改第三项
colors[3] = "brown"; // 新增第四项
复制代码
方括号中的索引表示要访问的值。如果索引小于数组中的项数,则返回对应项的值,就像这个例子中的colors[0]
会显示"red"。设置数组的值也使用相同的语法,但会替换指定位置的值。如果设置某个值得索引超过了数组现有项数,如这个例子中的colors[3]
所示,数组会自动添加到该索引值加1的长度(就这个例子而言,索引是3,因此数组的长度就是4)。
数组的项数保存在其length
属性中,这个属性始终会返回0或更大的值,如下面这个例子所示:
var colors = ["red","blue","green"];
var names = [];
alert(colors.length); // 3
alert(names.length); // 0
复制代码
数组的length
属性很有特点-它不是只读的。因此,通过设置这个属性,可以从数组的末尾移除项或向数组中添加新项。请看下面的例子:
var colors = ["red","blue","green"];
colors.length = 2;
alert(colors[2]); // undefined
复制代码
这个例子中的数组colors
一开始有3个值。将其length
属性设置为2会移除最后一项(位置为2的哪一项),结果再访问colors[2]
就会显示undefined
了,如果将其 length
属性设置为大于数组项数的值,则新增的每一项都会取得undefined
值,如下显示:
var colors = ["red","blue","green"];
colors.length = 4;
alert(colors[3]); // undefined
复制代码
在此,虽然colors
数组包含3个项,但把它的length
属性设置成了4。这个数组不存在位置3,所以访问这个位置的值就得到了特殊值undefined
。
利用length
属性也可以方便地在数组末尾添加新项,如下所示:
var colors = ["red","blue","green"]; // 创建一个包含3个字符串的数组
colors[colors.length] = "black"; // (在位置3)添加一种颜色
colors[colors.length] = "brown"; // (在位置4)再添加一种颜色
复制代码
由于数组最后一项的索引值始终是length-1,因此下一个新项的位置就是length。每当在数组末尾添加最后一项后,其length
属性就会自动更新以反应这一变化。换句话说,上面例子第二行中colors[colors.length]
的位置3添加了一个值,最后一行的colors[colors.length]
则为位置4添加了一个值。当把一个值放在超出当前数组大小的位置上时,数组就会重新计算其长度值,即长度值等于最后一项的索引加1,如下面的例子所示:
var colors = ["red","blue","green"];
colors[99] = "black";
alert(colors.length); // 100
复制代码
在这个例子中,我们向colors
数组的位置99插入了一个值,结果数组新长度(length)就是100 (99+1)。而位置3到位置98实际上是不存在的,所以访问它们都将返回undefined
5.2.1 检测数组
对于一个网页,或者全局作用域而言,使用instanceof
操作符就能得到满意的结果:
if(value instanceof Array) {
// 对数组执行某些操作
}
复制代码
instanceof
操作符的问题在于,它假定只有一个全局执行环境。如果网页中包含多个框架,那实际上就存在两个以上不同的全局执行环境,从而存在两个以上不同版本的Array
构造函数。如果你从一个框架向另一个框架传入一个数组,那么传人的数组与在第二个框架中原生创建的数组分别具有各自不同的构造函数。
为了解决这个问题,ECMAScript5
新增了Array.isArray()
方法。这个方法的目的时最终确定某个值是不是数组,而不管它是在哪个全局执行环境中创建的。这个方法的用法如下:
if(Array.isArray(value)) {
// 对数组执行某些操作
}
复制代码
支持Array.isArray() 方法的浏览器有IE9+、Firefox4+、Safari5+、Opera 10.5+和chrome。
5.2.2 转换方法
所有对象都具有toLocalString()
、toString()
和 valueOf
方法。其中,调用valueOf()
返回的还是数组本身,而调用数组的toString()
方法会返回由数组中每个值的字符串形式拼接而成的一个以逗号分割的字符串。实际上,为了创建一个字符串会调用数组每一项的toString()
方法。来看下面这个例子。
var colors = ["red","blue","green"];
alert(colors.toString()); // red,blue,green
alert(colors.valueOf()); // red,blue,green
alert(colors);
复制代码
在这里,我们首先显示地调用了toString()
方法。以便用于返回数组的字符串表示,每个值的字符串表示拼接成一个字符串,中间以逗号进行分隔。接着调用valueOf()
方法,而最后一行代码直接将数组传递给了alert()
。由于alert()
接收字符串参数,所以它会在后台调用toString()
方法,由此会得到与直接调用toString()
方法相同的结果。
另外,toLocalString()
方法经常也会返回与toString()
和valueOf()
方法相同的值,但也不是总是如此。当调用数组的toLocaleString()
方法时,它也会创建一个数组值的以逗号分割的字符串。但与前两个方法唯一的不同之处在于,这一次为了取得每一项的值,调用的是每一项的toLocale-String()
方法,而不是toString()
方法。请看下面这个例子。
var person1 = {
toLocaleString: function() {
return "Nikolaos";
},
toString: function() {
return "Nikolaos";
}
};
var person2 = {
toLocaleString: function() {
return "Grigorios";
},
toString: function() {
return "Greg";
}
}
var people = [person1, person2];
alert(people); //
复制代码
5.2.3 栈方法
ECMAScript
数组也提供了一种让数组的行为类型于其他数据结构的方法。具体说来,数组可以表现就像栈一样,后者是一种可以限制插入和删除项的数据结构。栈是一种LIFO
(Last-In-First-Out 后进后出)的数据结构,也就是最新添加的项最早被移除。而栈中项的插入(叫做推入)和移除(弹出),只发生在一个位置-栈的顶部。ECMAScript
为数组专门提供了push()
和pop()
方法,实现类似栈的行为。
push()
方法可以接收任意数量的参数,把他们逐个添加到数组末尾,并返回修改后数组的长度。pop()
方法则从数组末尾移除最后一项,减少数组的length值,然后返回移除的项,请看下面的例子:
var colors = new Array();
var count = colors.push("red","green");
alert(count); // 2
count = colors.push("black");
alert(count);
var item = colors.pop();
alert(item); // "black"
alert(colors.length); // 2
复制代码
5.2.4 队列方法
栈数据结构的访问规则是LIFO(后进先出),而队列数据结构的访问规则是FIFO(First-In-First-out)先进先出。在队列在列表的末尾添加项,从列表的前端移除项。由于push()
是向数组末端添加项的方法,因此要模拟队列只需一个从数组前端取得项的方法。实现这一操作的数组方法就是shift()
,它能够移除数组中第一个项并返回该项,同时将数组的长度减1。结合使用shift()
和push()
方法,可以像使用队列一样使用数组。
var colors = new Array();
var count = colors.push("red","green");
alert(count); // 2
count = colors.push("black");
alert(count);
var item = colors.shift();
alert(item); // "red"
alert(colors.length); // 2
复制代码