前言:
其实作为一个Java程序员,对JS程序一直都有点“不屑一顾”的感觉,很多人肯定和我一样,有其他语言基础,JS语法根本就懒得看,直接写程序,一般工作也都够用了。但是最近在做一个偏Web Excel项目,需要大量的JS编程和优化,抽空又“恶补”了下JS基础。发现原来对JS的理解偏差还是很大的。不过JS这个东西深入起来其实比Java要容易的。
基础:
JS数组和Java数组很类似,值都是有序的,索引从0开始。但是JS数组最大可能的索引为2的32次最大能容纳4294967295个元素。但是和Java数组不同的是,JS数组是动态的,不用指定初始大小,可以是稀疏的,下标不一定连续。访问到不存在的元素则返回undefined。最重要的是JS数组贯穿了JS中一切都是对象的概念,JS数组可以当成普通对象处理,这也是基于索引访问JS数组的“实质”。
一切都是对象:
JS中一切都是对象(单身狗又要落泪了),数组是对象的特殊形式。使用括号访问数组元素就像用方括号访问对象的属性一样。JS会把数字索引转换为字符串形式:1 -> “1”。所以这导致了JS数组的下标可以不连续,也就是a[2]后面可以直接跟a[5]而不存在a[3]和a[4]。
特殊点:
JS数组的特别之处在于,当使用非负整数作为属性名时JS数组会自动维护length属性值。Java的length属性是在初始时指定的,不会动态维护。
数组是特殊的对象,可以为其创建任意名字的属性,但是如果使用的属性是数组的索引(也就是说用数字访问数字索引),数组的特殊行为就是将根据需要更新它们的length属性。
在早期浏览器中,使用JS数组效率并不是很高,原因就是用数组索引方式访问数据,JS引擎搜索JS数组对象耗时和访问普通属性是差不多的,甚至更差。但是现代浏览器很多JS引擎都优化过这部分功能了,所以用索引的方式还是蛮快的。至于会不会比查询普通属性要快没有验证过。JS数组在维护length值是有两个特殊行为:
1.如果某个元素的index大于或者等于length,则length变为index + 1;
2.如果设置length小于某个值,那么index大于和等于length的元素全部被删除;
注意点:
在Java中数组的length属性是只读的,Java数组的length属性是被标记为final的,所以无法运行时修改,但是JS是允许我们读取和修改的。
访问JS数组元素时应该注意的是我们是给对象创建了一个属性还是访问的数组元素。这影响的是JS length属性的值。
比如:
a[“a”]在数组中也是允许的不过它访问的是数组对象a的属性a
a[1.00] 等同 a[1] 等同 a[“1”] 等同a[“1.0”],他们都访问的是数组对象a的第一个元素,a会委会length属性。
遍历优化
由于JS属于解释性语言,JS查询局部变量比对象变量要快,它不用去原型链查找迭代,所以很多时候JS优化都会用一个局部变量引用一些查询层次比较高的变量。所以JS数组遍历优化主要是两个,一个是针对length属性,另一个是针对数组元素,用两个局部变量缓存他们能提高些效率。
var temp = null;
for(var i = 0 , len = keys.length ; i <len ; i++) {
temp = a[i];
if(temp) continue; //null,undefined和不存在
}
稀疏数组
JS数组也分为稀疏数组和稠密数组,但是JS稀疏数组和Java的是不一样的。JS中足够稀疏的数组通常在实现上比稠密的数组更慢,但是内存利用率更高。
用数组直接量(就是 var a= []方式)不会创建稀疏数组,在JS数组中省略的元素是undefined这和元素不存在是有微妙的区别的。在Java中省略不初始化,数组元素都是null,也就是它是占有内存空间的,但是JS中不一样。在JS中可以用in监测数组元素是否存在:
var a =[,,]
0 in a;
JS数组——队列——栈的关系
JS数组是一个对象,所以可以认为它是一个Map,实际上JS的对象都可以认为是一个Map,所以在JS中我们没必要太过于去实现一个HashMap。在Java中我们通过数组通常会实现Stack和queue两种数据结构。在JS中JS数组提供了一些列方法,让JS本身就具有这两种数据结构的行为。
(1)栈行为:JS数组拥有push和pop方法,同数据结构中规定的push和pop是一样的。
(2)队列行为:JS数组还拥有unsift,shift方法,用来向对头插入、弹出数据,结合push和pop可以进行出队、入队操作。
(3)JS数组比较麻烦的是删除中间元素,比如要删除a[2],可以用delete或者splice方法,但是都不是很完美。
其他方法:
(1)join连接数组成一个字符串
(2)reverse颠倒元素
(3)sort排序数组
传入一个function返回一个数值,小于0则交换位置
(4)concat连接两个数组
(5)slice返回指定数组的一个片段或子数组
JS数组还有很多其他“奇妙”用途,和优化要点。看来每种语言都不可小觑。