Javascript 里的数组对象构建自 Array 构造器. 比如:
var ary = new Array(1, 2, 3 ) 或者 var ary = [ 1, 2, 3 ]
在 java 里, 数组会按照索引连续分配有序个元素.
而在 javascript 里, 数组的存取方式跟普通对象一模一样.
比如
1 2 3 4 5 |
var a = []; a[0] = 0 和 var a = {} a["0"] = 0 |
这 2 者的存取方式几乎一致. 都是对一个属性表进行存取操作. 所以以为用数组来存取数据比用 object 性能更高的说法未必一定是对的.
1 2 3 4 5 6 7 8 9 |
var obj = {0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9} var ary = [0,1,2,3,4,5,6,7,8,9] for ( var i = 0; i < 10; i++ ){ Obj[i] } for ( var i = 0; i < 10; i++ ){ ary[i] } |
这 2 个循环在 chrome 下测试, 花费的时间完全一致.
前面说 array 对象和 object 对象属性存取的方式几乎一致, 之所以说几乎是因为在某些引擎下 (测试过 chrome 和 firefox 都是如此), 用 for in 来遍历 array 对象, 引擎会对 key 进行排序, 比如 0 总是排在 1 之前.
1 2 3 4 5 6 |
var ary = [] ary[1] = 1 ary[0] = 0 for( var i in ary ){ alert (i) //ie: 1,0. chrome: 0,1 } |
Array 也是从 Function 构造而来.
1 |
Array.__proto__ === Function.prototype //true |
跟普通的对象最大的不同就是, array 对象有个被引擎自动维护的 length 属性, length 属性可读写但不能被枚举. 当调用 push, shift 等方法时. length 的值会被引擎更改. 而对 length 进行写操作时, ary 对象的属性表也可能被更改.
1 2 3 4 5 6 7 8 |
var ary = [1,2,3]; alert (ary.length); ary.push(4); alert (ary.length); ary.length = 2; for (var i in ary){ alert (ary[i]) } |
说到 Array, 就得顺便说说 arguments.
arguments 是 AO( activation object, 活动对象 ) 的一个属性, 看看它的 [[class]] 是什么.
1 2 3 |
(function(a,b,c){ alert ( Object.prototype.toString.call( arguments ) ); //[object Arguments] })(0,1,2) |
打印出来是 Arguments, 但 arguments 本身却是由 Object 构造.
1 2 3 |
alert ( Arguments ) //undefined. alert (arguments.constructor) //Object arguments.__proto__ === Object.prototype //true |
由此可见, arguments 对象也是一个普通的 Object 对象, 它无法使用 push, shift 等 Array 原型链上的方法.
在上例中, arguments 的结构类似于
1 2 3 4 5 6 7 8 9 |
{ 0: 0, 1:1, 2:2, length: 3, //dontEnum callee: function(){} //dontEnum __proto__: Object.prototype //dontEnum } |
我们经常需要把 arguments 当成数组来使用.
1 2 3 4 |
(function(a,b,c){ Array.prototype.push.call( arguments, 3 ); alert ( arguments.length ) //4, 成功添加了一个元素. })(0,1,2) |
为什么 arguments 可以被当成 array 的对象, 进行 push 操作. 为了搞清这个, 只有翻看引擎源码最靠谱.
看看 v8 的实现.
1 2 3 4 5 6 7 8 9 |
function ArrayPush() { var n = TO_UINT32(this.length); //上例中, this是arguments var m = %_ArgumentsLength(); for (var i = 0; i < m; i++) { this[i+n] = %_Arguments(i); //属性拷贝 } this.length = n + m; //修正length return this.length; } |
可以清楚的看到, 实际上 push 也就是一个属性拷贝的过程, 顺便修正了 length 属性. 至于 this 是谁, 并没有做任何校验. 因为 TO_UINT32 操作的存在, 甚至不需要 this 这个对象拥有 length 属性, 如果没有, 引擎会把 length 设置为 0.
不难看出, 只要满足这 2 个条件, 任何对象都可以冒充 array 调用 push 方法。
1 此对象本身要可存取属性.
2 length 属性可读写.
第 1 点很好理解, 前面说过了 push 就是一个属性拷贝的过程,看看下面的例子.
1 2 3 |
var a = 1; Array.prototype.push.call(a, "first") alert (a.length); //undefined |
第二点从 v8 的代码里也能清楚看到, 因为 this.length = n + m; 这一句的关系, 要求该对象的 length 属性是可写的. 回忆下 function.length. 这个 length 就是一个只读的属性,表示 function 形参的个数. 所以如果使用下面的代码, 还是会有问题.
1 2 3 4 |
var a = function(){}; Array.prototype.push.call( a, "first" ); alert (a[0]) //first, 属性拷贝的过程OK. alert (a.length); // 0, a的length不可写 |
另外,IE 低版本中此对象必须有一个显式并且有效的 length 属性, 猜测是这些引擎中没有 TO_UINT32 这个操作, 待大哥们验证.
来看看一个顺利的例子
1 2 3 4 |
var obj = {} Array.prototype.push.call( obj, ''first" ); alert ( obj.length ); //1 alert( obj[0] ) // 'first" |
ClementsL8o 2014 年 3 月 21 日
Leather Messenger Bags are the New Business Bag
Leather Messenger Bags are the New Business Bag
Traditionally, the typical business bag would have been a rigid leather briefcase, portfolio, satchels or attach?case. Things have changed and you just have to go to Canary Wharf or Wall Street to r
wjfgycvz 2013 年 11 月 20 日
Arrogance Jordans conna?t un succès immédiat exquisiteness à une recrue de haut vol ainsi que l’une des meilleures campagnes de marketing mis en in calm notable Weiden et Kennedy. Jordan chaussures ont été le additional vendu signature chaussure de basket Nike qui ait jamais produit. ? En additional de la signature Relish Jordans , Jordan Replace a une présence importante dans le basket-ball et le marché de cachet de vie. Malgré le fait que Michael Jordan a pris sa retraite du basket-ball en 2003 ( flood la 3ème fois ) Advised Jordans sont toujours les modèles les asset vendus nigh the bucketful de nombreux détaillants de baskets . Air Jordan 19 Homme
L’héritage de Michael Jordan vit avec la sortie de nouvelles Jordans chaque année et re- libéedibles de rétro Unveil Jordans .
Retro Presumption Jordan chaussures sont des remakes de l’ Eagerness Jordans classiques , soit dans les couleurs Mike portait retour dans la journée , ou légèrement modifiées teem correspondre aux tendances actuelles . à partir de 2005 , Jordan Courteous a ramené plusieurs “hybrides” chaussures Jordan qui prennent des composants individuels de différents Haughtiness Jordans et forment une chaussure de personne . ? Dans le cadre de la célébration de l’année 23, Jordan Manufacturer a lancé une campagne ” fusion ” multi- année, la Revitalize Coerce 1 avec Zephyr Jordans créer les Fusions Breath Jordan .
html6game 2012 年 9 月 16 日
现在据说 ff18 新增加了个 js 引擎,效率还不知道,但肯定要比之前的好,不知道如果用在 firefox os 里面是否能够直接运行,如果是,这将会是下一个开发点,使用脚本就能完成很多界面功能,包括对数据的直接操作。js 偶了解的不多,但它已经成为未来前端开发的热点,并且它的 jq 已经成为标准,想必 ie10 64bit 对它的优化也已经达到一个能够正常运行的程度,可能未来 chrome ff ie 处于同一个层次,在 debug 效率上。
deleted 2012 年 9 月 17 日
木有听懂
rex 2012 年 9 月 11 日
看到 array 我就想到 sort 方法,它接受一个函数作参数,函数的返回值只对正数负数有效,如果返回 0 会出现随机排序的结果。不知博主是否测试过,如果属实的话那对数组随机排序就简单多了
rex 2012 年 9 月 11 日
svenzeng 2012 年 9 月 11 日
返回 0 应该是原顺序不变吧。
rex 2012 年 9 月 13 日
如果按照规定的写,比如
function cmp(a,b){ return a-b>0?1:-1 }
这样会如期的按升序排。
要是不按规定写,如:
function cmp(a,b){ return a-b>0?1:0 }
function cmp(a,b){ return -1 }
function cmp(a,b){ return 0 }
就出现貌似无规律的排序,不知道这是为何呢?
svenzeng 2012 年 9 月 13 日
标准只规定了函数体中 a b 这几种情况. 否则不保证稳定的返回顺序.
刚才这种情况, 具体还是要看各引擎的实现. 实际上在 SpiderMonkey 和 v8 中, 返回的顺序不会变, 而 Jscript 中会错乱. 这没什么不对, 因为标准就是这样规定的..
svenzeng 2012 年 9 月 13 日
a > b, a = b, a < b
svenzeng 2012 年 9 月 13 日
刚翻了下 v8 的代码.
comparefn 的返回值只负责交换元素在数组中的位置.
比如
[1,2,3,4,5].sort(function( a, b ){
return 1;
})
//[5,4,3,2,1]
相当于翻转数组.
a 和 b 的大小关系才负责真正的排序.
svenzeng 2012 年 9 月 13 日
刚翻了下 v8 的代码.
comparefn 的返回值只负责交换元素在数组中的位置. 比如:
[1,2,3,4,5].sort(function( a, b ){
return 1;
})
结果是 [5,4,3,2,1], 相当于翻转数组.
a 和 b 的大小关系才负责真正的排序.
VILIC 2012 年 9 月 9 日
关于数组在浏览器下的遍历速度, 原来测试过 Chrome 的, 大约能达到 C++原生数组速度的 1/3, 远超 vector. 想必是与 Chrome 的优化有关, 据说是局部编译? 不是很清楚. 但既然能达到这个速度, 我想不是使用 hash 能够比较的?
匿名 2012 年 9 月 5 日
var ary = []
ary[1] = 1
ary[0] = 0
for( var i in ary ){
alert (i) //ie: 1,0. chrome: 0,1
}
ie 下返回 1,0 你测试了吗?
匿名 2012 年 9 月 5 日
经测试,ie9 下的返回结果并不是博主所说。
ie9 的结果跟 firefox 的结果与博主所说的 chrome 结果是相同的。
svenzeng 2012 年 9 月 5 日
我测试的 IE8. 跟具体引擎的实现有关吧.
匿名 2012 年 9 月 5 日
ie9 浏览器下的兼容模式(ie7,ie8),结果是一样的。
svenzeng 2012 年 9 月 5 日
关于这个, 我觉得只要记住 set 的顺序在 get 的时候, 不可以信赖就行了
TooBug 2012 年 9 月 3 日
Object.prototype.toString.call( arguments )
这个可以看出 arguments 的构造函数么?跟 arguments.toString 是等价的吧,仅仅是说 arguments 本身的类型是 [object Arguments] 吧。
svenzeng 2012 年 9 月 3 日
嗯, 构造函数是 Object. 应该说 [[Class]] 已修改, 多谢指正.
JimLiu 2012 年 9 月 3 日
不错哦~
svenzeng 2012 年 9 月 4 日
3Q~