第7章 数组

来源:互联网 发布:淘宝商家后台登陆 编辑:程序博客网 时间:2024/05/08 12:10

7.数组

数组是值得有序集合。每个值叫做一个元素,而每个元素在数组中有一个位置,以数字表示,成为索引。

 数组是JavaScript对象的特殊形式,数组索引实际上和碰巧是整数的属性名差不多。通常数组是经过优化的,用数字索引来访问数组元素一般来说比访问常规的对象属性要快的多。

7.1 数组创建

<pre name="code" class="html">方法一:使用直接量创建数组
var empty = [];//创建一个没有元素的数组var primes = [1,true,{x:"x"},4,5,]//创建一个有5个元素的数组,元素类型不同var count = [1,,3];//数组元素有3三,中间的那个元素值为undefinedvar undefs = [,,]//数组元素有两个,都是undefined //注意:直接量创建数组的语法允许有可选的结尾逗号

方法二:使用构造函Array()创建数组var a = new Array();//等同于var a = [];var a = new Array(10);//创建length等于10的数组。//注意数组中没有存储值,索引属性“0”、“1”等还没有定义var a = new Array(5,4,3,"testing",true);//构造函数的参数将会成为新数组的元素。这里需要注意,如果构造函数只有一个参数,并且是数值类型的,那么这个参数为数组的长度。如果构造函数有两个或多个参数,或只有一个非数值类型的参数是,那么这些参数为数组的元素。

7.2数组元素的读和写

使用[]操作符来访问数组中的一个元素。数组的引用位于操作符的左边。方括号中是一个返回非负整数值得任意表达式。使用该语法既可以读又可以写一个元素。事例代码如下:

var a = ["world"];var value = a[0];//读第0个元素a[1] = 3.14;//写第1个元素
请记住,数组是对象的特殊形式。使用方括号访问数组就像使用方括号访问对象属性一样。JavaScript将指定的数字索引转换成字符串----------索引值1变成“1”-------------然后将其作为属性名来使用。

关于索引值从数字转换成字符串没用什么特别之处:常规对象也可以这么做,如下:

var o = {};
o[1] = "one";//相当于给对象o添加了一个“1”属性名
o[1];//获取属性“1“的值
o.1;//但是这种通过点来获取的方式是错误的,不会通过编译

对于通过点(.)运算符来获取对象的属性的值时,运算符左侧是对象的引用,右侧必须是一个以属性名称命名的标示符(标示符必须以字符、下划线(_)、美元符($)号开始)。

对于通过方括号([])运算符来获取对象的属性的值时,运算符左侧是对象的引用,右侧必须是一个计算结果为字符串的表达式。


清晰地区分数组索引和属性名是非常有用的。所有的索引都是属性名,但只有在0~2的32次方-2之间的整数属性名才是索引。

注意:可以使用负数和非整数来索引数组。这种情况下,数值将转换成字符串,字符串作为对象的属性名来使用。数组的length属性不会改变。如下:

var a = [];//别忘了数组也是一个对象,只不过是对象的一种特殊形式而已
a[-10] = "负十";
console.log(a[-10]);//=>负十
console.log(a.length);//=>0

同样,如果使用了非负整数的字符串。这中情况下,非负整数的字符串将会转换成非负整数,非负整数将作为数组的索引,而非对象的属性。如下:

var a = [];
a["0"] = "零"; 
console.log(a[0]);//=>零
console.log(a.length);//=>1

也就说数组方括号中的值可以隐式的转换成非负整数的,就会被当做数组索引,否则就会被当做数组的属性。在比如:
a[1.000] //1.000可以隐式的转换成非负整数1   //等同于a[1]


7.3稀疏数组

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

方式一:使用Array()构造函数来创建稀疏数组

var a = new Array(5);//数组没有元素,a.length是5

方式二:指定数组的索引值大于当前的数组长度

var a = [];//a.length为0a[0] = "零";a[5] = "五";//给数组添加一个元素,a.length为11console.log(Object.keys(a));//<span style="font-family: Arial, Helvetica, sans-serif;">=></span><span style="font-family: Arial, Helvetica, sans-serif;">["0","5"]  //索引不连续,是稀疏数组。这里也可以这么理解-----数组对象a没有属性1、2、3、4、属性名。</span>

方式三:用delete操作符来产生稀疏数组。

var a = [1,2,3];delete a[1];console.log(1 in a);//=> false 

这一节中有这么一段话和代码,如下:
"注意,当在数组直接量中省略值时不会创建稀疏数组。省略的元素在数组中是存在的,其值为undefined。"

var a1 = [,,,];//数组是[undefined,undefined,undefined]var a2 = new Array(3);  //该数组根本没有元素0 in a1// => true:a1索引0处也有一个元素0 in a2        // => false:a2索引0处没有元素

实际将上几行代码复制到浏览器(IE8和谷歌[版本 33.0.1750.146 m])中运行,第三行和第四行输出的结果都是false,也就说在对象直接量中省略值(使用了连续的逗号)时是会创建稀疏数组的。而不是像书中写的"当在数组直接量中省略值时不会创建稀疏数组"。

不知道是原著有误,还是翻译有误,还是不同浏览器所导致的错误。个人理解应该没有错误,因为实际运行的结果证明了书上所写是错误的。ps:望高人指点。

 我们在实际开发中很少使用和碰见稀疏数组,但是了解稀疏数组是了解JavaScript数组的真实本质的一部分。这有利于我们更好的了解JavaScript数组。

如果我们确实碰见了稀疏数组,你的代码很可能像对待非稀疏数组一样来对待它们,只不过返回值是undefined。


7.4数组长度

每个数组都有个一个length属性,就是这个属性使其区别于常规的javaScript对象。针对稠密数组(也就是非稀疏数组),length属性值代表数组中元素的个数。其值比数组中最大的索引大1。

当数组是稀疏数组时,length属性的值大于数组中元素的个数。

数组长度总是保证大于它的每一个元素的索引值。或者换一种说法,在数组中(无论是稀疏或非稀疏)找不到一个元素的索引值大于或等于

数组长度。为了维持次规则不变,数组有两个特殊的行为。

第一个特殊的行为:如果为一个数组元素赋值,它的索引i大于或等于现有数组的长度时,length属性的值将设置为i+1。

第二个特殊的行为:如果设置length属性为一个小于当前长度的非负整数n时,当前数组中那些索引值小于或等于n的元素将从数组中删除。事例如下:

var a = [1,2,3,4,5];a.length = 3;console.log(a.toString());//=><span style="box-sizing: border-box; color: rgb(34, 34, 34); font-family: Consolas, 'Lucida Console', monospace; white-space: pre-wrap;">1,2,3</span><span style="color: rgb(34, 34, 34); font-family: Consolas, 'Lucida Console', monospace; white-space: pre-wrap;"> </span>a.length = 1;console.log(a.toString());//=>1
也可以将length属性值设置为大于当前数组长度。这时的数组是一个稀疏数组。

7.5数组元素的添加和删除

添加数组元素有以下几种常见方式:

方式一:为新索引复制

var a = [];a[0] = "zero";

方式二:使用push()方法在数组尾部增加一个或多个元素
var a = [];a.push(''zero');a.push("one","two");
在数组的尾部添加一个元素与个a[a.length]赋值是一样的。

方式三:使用unshift()方法在数组的首部插入一个元素,并将其它元素依次移到高索引处。

var a = ["zero","one"];a.unshift("new_zero");console.log(a.toString());//=> <span style="color: rgb(34, 34, 34); font-family: Consolas, 'Lucida Console', monospace; white-space: pre-wrap;">new_zero,zero,one</span>

删除数组元素有以下几种方式:

方式一: 使用delete运算符来删除数组元素

var a =[1,2,3];delete a[1];console.log(1 in a);//=>falseconsole.log(a.length);//=>3 //注意使用delete运算符删除数组元素不会改变length属性,这是会产生稀疏数组

方式二: 使用pop()方法删除并返回数组中的最后一个元素(一般情况下和push()一起使用),数组length数组减1
var a = [1,2,3];console.log(a.pop());//=>3console.log(a.length);//=>2
方式三:使用shift()方法删除并返数组中的第一个元素(一般情况下和unshift()一起使用),数组length属性减1
var a = [1,2,3];console.log(a.shift());//=>1console.log(a.length);//=>2


最后,还有一个splice()是一个通用的方法来插入、删除、或替换数组元素。详见 7.8节数组方法。

7.6数组的遍历

使用for循环是遍历数组元素最常见的方法:
var o = {x:"x",y:"y"};var keys = Object.keys(o);var values = [];for(var i=0;i<keys.length;i++){var key = keys[i];values[i] = o[key];}console.log(values.toString());//=> x,y

在嵌套循环中和其他性能重要的上下文中,可以看到这种基本的数组遍历需要优化,数组的长度应该只查询一次而非每次都要查询:
for(var i=0;l=keys.length;i<l;i++){//循环体内容不变}
假设数组都是稠密的,并且所有元素都是合法的。否则,使用数组元素之前应该先检测他们。比如想要排除null、undefined、和不存在的元素。代码如下:
for(var i=0;i<a.length;i++){if(!a[i]) continue;// 跳过null、undefined和不存在的元素}for(var i=0;i<a.length;i++){if(a[i] === undefined) continue;//跳过undefined和不存在的值}for(var i=0;i<a.length;i++){if(!(i in a)) continue;//跳过不存在的值}


还可以使用for/in循环处理稀疏数组。循环每次将一个可枚举的属性名赋给循环变量。不存在的将不会遍历到:

for(var index in sparseArray){var value = sparseArray[index];}

for/in循环可以枚举继承的属性名。如果不想用for/in 循环枚举继承的属性,需要使用一些额外的检测方法过滤掉继承属。检测方法如下:

<pre name="code" class="javascript">for(var i in a){if(a.hasOwnProperty(i)) continue;//跳过继承属性}


for/in循环不仅可以枚举索引属性,也可以枚举对象属性。以下代码通过检测过滤了数组对象的对象属性:

var a = ["zero","one","two"];a["p"] ="属性p的值";for(var i in a){//跳过不是非负整数的i(也就是跳过对象属性)if(String(Math.floor(Math.abs(Number(i)))) !== i) continue;console.log(a[i]);//"zero","one","two" //注意这里没有输出属性p的值}

ECMAScript 5 定义了一些遍历数组元素的新方法。这些方法中最常用的就是forEach()方法。

var data = ["one","two","three"];data.forEach(function(value, index, t){//value:数组中的元素 index:数组索引 t:数组本身console.log(value, index, t);});
forEach()和相关的遍历方法使得数组本身拥有简单而强大的函数式编程风格。


7.7 多维数组

JavaScript不支持真的多维数组,但可以使用数组的数组来近似。访问数组中数组的元素,只要简单的使用两个[]操作即可。
这里有个例子,它使用二维数组作为九九乘法表:

//创建一个多维数组var table = new Array(10);//表格有10行for(var i=0;i<table.length;i++)     table[i] = new Array(10);//表格有10列//初始化数组for(var row=0;row<table.length;row++){     for(var col=0;col<table[row].length;col++){          table[row][col] = row*col;     }}//使用多维数组来计算(查询) 5*7console.log(table[5][7]);


7.8数组方法

ECMAScript 3在Array.prototype中定义了一些很有用的操作数组的函数,这意味着所有数组对象都能使用这些函数。

省略对数组方法的介绍。想了解的话,去网上查,或者去看 JavaScript权威指南 第六版。





0 0
原创粉丝点击