Array类型
除了Object之外,Array类型恐怕是ECMAScript中最常用的类型了。而且, ECMAScript中的数组与其他多数语言中的数组有着相当大的区别。虽然ECMAScript数组与其他语言中的数组都是数据的有序列表,但与其他语言不通的是,ECMAScript数组的每一项可以保存任何类型的数据。也就是说,可以用数组的第一个位置保存字符串,用第二个位置保存数值,用第三个位置保存对象,以此类推。而且,ECMAScript数组的大小是可以动态调整的,即可以随着数据的添加自动增长以容纳新增数据。
创建数组的基本方式有两种。第一种是使用Array构造函数,如下:
var colors = new Array();
alert(colors.length); //0
如果预先知道数组要保存的项目数量,也可以给构造函数传递该数量,而该数量会自动编程length属性的值。例如,下面的代码将创建length值为20的数组。
var colors = new Array(20);
alert(colors.length); //20
也可以向Array构造函数传递数组中应该包含的想。以下代码创建了一个包含3个字符串值的数组:
var colors = new Array("red", "blue", "green");
alert(colors[0] + " " + colors[1] + " " + colors[2]); //red blue green
alert(colors.length); //3
当然,给构造函数传递一个值也可以创建数组。但这个时候问题就复杂一点了, 因为如果传递的是数值,则会按照该数值创建包含给定项数的数组, 如果传入的数值是负值的话,将会报错;而如果传递的是其他类型的参数,则会创建包含那个值的只有一项的值。如下:
var colors = new Array(3);
alert(colors[0]); //undefined
var names = new Array("Greg");
alert(names[0]); //Greg
var arr = new Array(-1);
alert(arr[0]); //Invalid array length
创建数组的第二种基本方式是使用数组字面量表示法。数组字面量由一对包含数组想的方括号表示,多个数组之间以逗号隔开,如下所示;
var colors = ["red", "blue", "green"];
alert(colors.length); //3
var names = [];
alert(names.length); //0
var values = [1,2,];
alert(values.length); //2
var options = [,,,,,];
alert(options.length); //5
以上代码的第一行创建了一个包含3个字符串的数组。第二行使用一对空方括号创建一个空数组names。第三行展示了在数组字面量的最后一项添加逗号的结果:在IE(IE8之前)中,values会成为一个包含3个项且每个项的值分别为1, 2 和 undefined的数组;在其他浏览器中,values 会成为一个包含2项目值分别为1 和 2的数组。第四行一系列的逗号创建了一个数组,在IE(IE8之前)中,options会成为一个包含6个项且每项的值都是undefined, 在其他浏览器中,options会成为一个包含5个项且每项的值都是undefined;由于IE8之前的实现和其他浏览器不一致,因此不建议使用这种语法。
在ECMAScript中,可以通过数组的length是属性置空,裁剪 和 扩容一个数组, 如下:
//置空一个数组
var arr = [1, 2, 3];
alert(arr[2]); //3
arr.length = 0;
alert(arr[2]); //undefined
arr.length = 3; //此时把数组的长度还原成原来的长度, 但是原来的值并不能复原
alert(arr[2]); //undefined
//裁剪一个数组
var arr = ["red", "blue", "green"];
alert(arr.length); //3
alert(arr[2]); //green
arr.length = 2;
alert(arr.length); //2
alert(arr[2]); //undefined
//扩容一个数组
var arr = ["red", "blue", "green"];
alert(arr.length); //3
alert(arr[2]); //green
arr.length = 5;
alert(arr.length); //5
alert(arr[4]); //undefined
需要注意的是: 当通过数组的length置空一个数组的时候,数组的值将不被保留,即使之后再将数组的长度设置为原来的长度值,原来的值也不能恢复; 裁剪一个数组和置空是一样的; 扩容一个数组的时候, 因未对扩容后的索引对应的值进行赋值,所以默认是undefined。
同样的,也可以巧妙的运用length属性为数据添加项,如下:
var arr = ["red", "blue", "green"];
alert(arr.length); //3
arr[arr.length] = "black"; //等价于 arr[3] = "black"
alert(arr.length); //4
arr[arr.length] = "brown"; //等价于 arr[4] = "brown"
alert(arr.length); //5
检测数组
在单一的全局执行环境中,检测一个变量是不是数组有两种方式:
var arr = ["red", "blue", "green"]; alert(arr instanceof Array); //true alert(Array.isArray(arr)); //true
但是如果网页中包含多个框架, 那么就会存在多个不同的全局执行环境,此时使用instanceof操作符将不能得到想要的结果,所以推荐使用 Array.isArray()方法检测数组。
转换方法
所有对象都具有 toLocaleString() , toString() 和 valueOf() 方法。其中调用数组的toString()方法会返回数组中每个值的字符串形式拼接而成的一个以逗号分隔的字符串。而调用valueOf() 返回的还是数组。实际上,为了创建这个字符串会调用数组每一项的toString()方法。如下:
var arr = ["red", "blue", "green"]; alert(typeof arr); //Object alert(arr); //red,blue,green alert(typeof arr.toString()); //string alert("toString -> " + arr.toString()); //red,blue,green alert(typeof arr.valueOf()); //Object alert("valueOf -> " + arr.valueOf()); //red,blue,green alert(typeof arr.toLocaleString()); //string alert("toLocaleString -> " + arr.toLocaleString()); //red,blue,green
toLocaleString() 方法经常返回与toString() 和 valueOf() 方法相同的值,但也不总是如此。当调用数组的toLocaleString()方法时,它也会创建一个数组的一逗号分隔开的字符串。而与前两个方法唯一的不同处在于,这一次为了取得每一项的值,调用的是每一项的toLocaleString()方法,而不是toString()方法。如下:
var person1 = { toLocaleString: function() { return "Nikolas"; }, toString: function() { return "Nicholas"; } }; var person2 = { toLocaleString: function() { return "Grigorios"; }, toString: function() { return "Greg"; } }; var people = [person1, person2]; alert(people); //Nicholas,Greg alert(people.toString()); //Nicholas,Greg alert(people.toLocaleString()); //Nikolas,Grigorios
上面这个例子中,在调用people.toLocaleString()方法的时候, 调用的是数组内元素的toLocaleString()方法;再看下面例子:
var person = { name : "Nicholas", age : 29 } var arr = ["red", "blue", "green", person]; alert("arr -> " + arr); //arr -> red,blue,green,[object Object] alert("valueOf -> " + arr.valueOf()); //valueOf -> red,blue,green,[object Object] alert("toString -> " + arr.toString()); //toString -> red,blue,green,[object Object] alert("toLocaleString -> " + arr.toLocaleString()); //toLocaleString -> red,blue,green,[object Object] 此时即没有重写person对象的toString() 方法, 也没有重写toLocaleString() 方法,通过上面的结果我们知道, person对象的toString()方法和toLocaleString()方法返回的都是[object Object] ; 再看下面: var person = { name : "Nicholas", age : 29 } person.toLocaleString = function() { return this.name + " -> " + this.age; } var arr = ["red", "blue", "green", person]; alert("arr -> " + arr); //arr -> red,blue,green,[object Object] alert("valueOf -> " + arr.valueOf()); //valueOf -> red,blue,green,[object Object] alert("toString -> " + arr.toString()); //toString -> red,blue,green,[object Object] alert("toLocaleString -> " + arr.toLocaleString()); //toLocaleString -> red,blue,green,Nicholas -> 29
此时因为没有覆盖person的toString()方法,所以person对象的toString()方法仍然是[object Object]; 因此, 调用数组的toString()方法, 返回的还是[object Object]; 但是因为覆盖了person的toLocaleString()方法, 所以返回的是 “Nicholas -> 29”; 再看下面:
var person = { name : "Nicholas", age : 29 } person.toString = function() { return this.name + " -> " + this.age; } var arr = ["red", "blue", "green", person]; alert("arr -> " + arr); //arr -> red,blue,green,Nicholas -> 29 alert("valueOf -> " + arr.valueOf()); //valueOf -> red,blue,green,Nicholas -> 29 alert("toString -> " + arr.toString()); //toString -> red,blue,green,Nicholas -> 29 alert("toLocaleString -> " + arr.toLocaleString()); //toLocaleString -> red,blue,green,Nicholas -> 29
此时覆盖了person对象的toString()方法,所以调用数组的toString()方法返回的是 “Nicholas -> 29”;再看下面:
var person = { name : "Nicholas", age : 29 } person.toString = function() { return this.name + " -> " + this.age; }; person.toLocaleString = function() { return this.name + " -> " + (this.age + 10); }; var arr = ["red", "blue", "green", person]; alert("arr -> " + arr); //arr -> red,blue,green,Nicholas -> 29 alert("valueOf -> " + arr.valueOf()); //valueOf -> red,blue,green,Nicholas -> 29 alert("toString -> " + arr.toString()); //toString -> red,blue,green,Nicholas -> 29 alert("toLocaleString -> " + arr.toLocaleString()); //toLocaleString -> red,blue,green,Nicholas -> 39
此时即覆盖了person的toString()和toLocaleString()方法, 所以在调用数组的toString()方法和toLocaleString()方法的时候,响应的调用了person的对应方法。
所以通过上面的对比我们可以知道:
1 : 在没有数组元素的toString() 和 toLocaleString() 方法的时候, 调用数组的toString()和toLocaleString()方法,则会自动调用数组元素的相对应的方法。
2 : 在覆盖了数组元素的toString()方法, 但是没有覆盖toLocaleString()方法的时候,调用数组的toLocaleString()方法的时候,调用的则是数组元素的toString() 方法。
备注: 摘取自《JAVASCRIPT高级程序设计:第3版》