JavaScript:数组的length属性
在ES5中,数组的length属性是这么规定的:
15.4.5.2 length
数组对象的length属性是⼀个数据属性,该属性的值始终从数值上⼤于所属数组的任何⼀个索引号.
length属性的初始特性为{ [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }.
数组的属性可以分为三种:length属性,索引属性,其他属性.和普通对象相⽐,数组对象特殊的地⽅就是它的length属性和索引属性,为了对数组的属性做特殊处理,ES5标准专门规定了⼀个数组专⽤的[[DefineOwnProperty]]内部⽅法(15.4.5.1),以区别于其他对象所⽤的[[DefineOwnProperty]]内部⽅法(8.12.9).
1. 修改数组的length属性会不会影响数组的索引属性?
数组的索引属性(通常称之为索引或下标)是那些属性名为数字形式的属性(实际上是字符串).⽽且数字范围必须处于0到232-2之间.
本节要讲的这些表现主要规定在ES5 15.4.5.1-3中.
1.1. 以赋值⽅式修改length属性:
以赋值⽅式只能修改length属性的值(也就是value特性),本节给出的例⼦在⽬前所有主流引擎上表现都相同.
1.1.1. ⼿动增⼤数组的length属性不会影响数组的索引属性:
> var a = [0,1,2,3,4]
> a
[0, 1, 2, 3, 4]
> a.length = 10
10
> a
[0, 1, 2, 3, 4, , , , , ,] //⼿动增⼤length属性并不会⾃动补全所缺少的索引属性,只是有些交互环境在显⽰数组的时候会把缺少的索引属性以空字符串+逗号的⽅式显⽰出来. > print(a)
0,1,2,3,4,,,,, //String⽅法也会把那些缺少的索引属性显⽰出来
> Object.keys(a)
["0", "1", "2", "3", "4"] //但实际上索引属性并没有增加,最⼤的索引属性还是4
> a.length = Math.pow(2,32)
RangeError: invalid array length //为length属性赋过⼤的值会抛出异常
1.1.
2. ⼿动减⼩数组的length属性会影响数组的索引属性:
> var a = [0,1,2,3,4]
> a
[0, 1, 2, 3, 4]
> a.length = 3
3
> a
[0, 1, 2] //⼿动减⼩length属性会截掉多出来的索引属性
> Object.defineProperty(a,"1",{configurable:false}) //如果需要截掉的索引属性中有⼀个是不可删除的,也就是不可配置的,那么...
[0, 1, 2]
> a.length = 1
1
>a
[0, 1] //截取操作会被这种不可删除的索引属性阻⽌
>a.length
2 //length属性也会被⾃动设置成为最⼤的索引号+1
1.2. 以定义⽅式修改length属性:
如果你还不知道对象属性的定义操作和赋值操作有什么区别,推荐看看我的另⼀篇⽂章.
以定义⽅式不仅能修改length属性的value特性,还能修改其他的特性⽐如writable特性.以定义⽅式修改数组的length属性在⽬前所有主流引擎上的表现有很多不同.
Chrome 25(v8):
>var a = [0,1,2,3,4]
>Object.defineProperty(a,"length",{value:10}) //以定义⽅式修改length属性的值
[0, 1, 2, 3, 4, undefined × 5]
>a.length //修改成功
10
>Object.defineProperty(a,"length",{writable:false}) //修改length属性为只读
[0, 1, 2, 3, 4, undefined × 5]
&OwnPropertyDescriptor(a,"length")
Object {value: 10, writable: false, enumerable: false, configurable: false} //length属性现在是不可配置加不可写的>a.length = 100 //以赋值⽅式修改length属性的值
100
>a.length //的确没有更改成功
10
>(function(){"use strict";a.length=100})() //严格模式下会报错
TypeError: Cannot assign to read only property 'length' of [object Array]
>Object.defineProperty(a,"length",{value:100}) //再以定义⽅式修改length属性的值
TypeError: Cannot redefine property: length //也不能修改
>a.push(10) //通过push⽅法修改数组
11
>a
[0, 1, 2, 3, 4, undefined × 5, 10] //push进去了
>a.length
11 //length属性也被修改了
>a[100] = 100 //添加新的索引元素
100
>a.length
101 //length属性也被修改了
Opera12.12(Carakan) :
opera中的表现和chrome基本相同.
IE9(Chakra):
IE9中的表现和chrome的区别是,length属性如果已经被重定义成只读的,则通过任何⽅式都不能修改它的值.
>> Object.defineProperty(a,"length",{value:100})
"⽆法修改不可写的属性“length”"
>> a.push(10) //抛出异常
"对象不⽀持此操作"
>> a[100] = 10 //因为不能修改length属性的值,所以这样的属性添加操作也会静默失败
10
>> a[100] + ""
"undefined"
>> a.length
10
Firefox 20(SpiderMonkey):
> var a = [0,1,2,3,4]
> Object.defineProperty(a,"length",{value:10})
InternalError: defining the length property on an array is not currently supported
//Firefox完全不⽀持重新定义数组的length属性,但未来会修复.详见
Safari 5.17(JavaScriptCore):
>var a = [0,1,2,3,4]
>Object.defineProperty(a,"length",{value:10}) //静默失败
[0, 1, 2, 3, 4]
>a.length
5 //length属性没有变
>Object.defineProperty(a,"length",{writable:false}) //静默失败
[0, 1, 2, 3, 4]
>JSON.OwnPropertyDescriptor(a,"length"))
"{"value":5,"writable":true,"enumerable":false,"configurable":false}" //属性描述符没有变
//Safari也完全不⽀持重新定义数组的length属性,但不抛出异常
哪个浏览器的表现是最合理的,这我不知道.但我们应该避免数组length属性的重定义操作,不过⼀般也不需要这样做.
2. 修改数组的索引属性会不会影响数组的length属性?
本节要讲的这些表现主要规定在ES5 15.4.5.1-4中.
2.1. 增⼤数组的最⼤索引号会影响数组的length属性 :
> var a = [0,1,2,3,4]
> a
[0, 1, 2, 3, 4]
> a[10] = 10
10
> a
[0, 1, 2, 3, 4, , , , , , 10] //这种数组通常称之为"稀疏数组",对应的是"密集数组"
> a.length
11 //length属性的值被⾃动更改为最⼤索引号10再加上1
> a[Math.pow(2,32)-1] = "x" //超过2^32-2的话(4294967295)
"x"
> a
[0, 1, 2, 3, 4, , , , , , 10] //4294967295不在索引⾥⾯
> a.length
11 //length属性的值没有变
>a[Math.pow(2,32)-1] //4294967295只能算个普通属性
"x"
2.2. 删除索引号最⼤的索引属性不会影响数组的length属性:
> var a = [0, 1, 2, 3, 4, , , , , , 10]
> a.length
11
> delete a[10]
true
javascript数组对象> a
[0, 1, 2, 3, 4, , , , , , ,] //数组现在只有5个索引属性
> a.length
11 //但length属性没有减⼩,还是11
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论