2013-04-07 78 views
6

我想下面的代码在ideone:Array.pop()乱数组的长度?

var a = []; 
a[0] = 0; 
a[5] = 5; 
a[6] = undefined; 
print("contents before popping:"); 
for(var e in a) print("\ta[", e, "] =", a[e]); 
print("a.length =", a.length); 
for (var i = 0; i < a.length; i++) 
    print("\ta.hasOwnProperty(", i, ") =", a.hasOwnProperty(i)); 

print("popping -->", a.pop()); 
print("popping -->", a.pop()); 
print("contents after popping:"); 
for(var e in a) print("\ta[", e, "] =", a[e]); 
print("a.length =", a.length); 
for (var i = 0; i < a.length; i++) 
    print("\ta.hasOwnProperty(", i, ") =", a.hasOwnProperty(i)); 

输出变为如下:

contents before popping: 
    a[ 0 ] = 0 
    a[ 5 ] = 5 
    a[ 6 ] = undefined 
a.length = 7 
    a.hasOwnProperty(0) = true 
    a.hasOwnProperty(1) = false 
    a.hasOwnProperty(2) = false 
    a.hasOwnProperty(3) = false 
    a.hasOwnProperty(4) = false 
    a.hasOwnProperty(5) = true 
    a.hasOwnProperty(6) = true 
popping --> undefined 
popping --> 5 
contents after popping: 
    a[ 0 ] = 0 
a.length = 5 
    a.hasOwnProperty(0) = true 
    a.hasOwnProperty(1) = false 
    a.hasOwnProperty(2) = false 
    a.hasOwnProperty(3) = false 
    a.hasOwnProperty(4) = false 

在我的JavaScript的书(当然,Crockford的),我读了数组的长度为最大的计算所有属性的数值。那么,为什么它的长度是5时,它最大的数字属性是0?谢谢!

回答

6

关于JavaScript的一个好处是,它的语义在形式上和标准中尽可能明确地定义。具体而言,section 15.4指出:

长度属性的值在数值上比每个属性的名字是一个数组索引的名称更大;每当创建或更改Array对象的属性时,都会根据需要调整其他属性以保持此不变量。

换句话说,每次你改变一个数组,其length调整,但是,它的唯一保证是不是max(indexes)更大,不一定等于max(indexes)+1。例如,pop method总是会删除length-1的第th个元素,并将length减1,无论数组实际包含多少个元素。

另外请注意,大多数数组方法是通用的,并且不需要专门知道有关数组的任何内容。他们可以操作任意对象,如果这样的对象碰巧有一个名为length的属性,它将根据上述规则进行调整。试想一下:

foo = { 
    length: 100, 
    99: 'hi' 
} 

alert([].pop.apply(foo)) // hi 
alert(foo.length)  // 99 

alert([].pop.apply(foo)) // undefined 
alert(foo.length)  // 98 

也就是说,在你的问题的情况下这是无关紧要如何准确阵列代表 - pop和朋友不要使用这些信息。

+0

我一直在通过这个小提琴来演示Array.length何时不可靠,除了你的例子。 http://jsfiddle.net/6WrkT/1/ – 2013-06-18 23:16:39

1

问题”是转让5

第二次你做到这一点,JavaScript数组得到充满了与undefined价值初始化的插槽。

所以调用

a[5] = 5; 

导致

[0, undefined, undefined, undefined, undefined, 5] 

然后你还可以创建a[6]undefined初始化它,我们得到

[0, undefined, undefined, undefined, undefined, 5, undefined] 

7.length

现在我们所说的.pop()(爱字doublepop),我们得到

[0, undefined, undefined, undefined, undefined] 

.length


事实上,正如在评论中指出的,这似乎仍然是非常奇怪的行为。初始化任何索引时,之前的插槽并不是真的被任何东西分配的。它创建了一个稀疏阵列。但话又说回来,如果我们去掉最后两个条目,有左(0),其次是undefined值(莫名其妙成为真正值,可能是因为我们手动分配一个6)只有一个值。

我想我们需要实现大师:)

+2

由于'hasOwnProperty'返回'false',所以数组没有被填充。 – 2013-04-07 10:19:22

+0

我不确定中间值是否初始化为undefined,我认为'a'是一个稀疏数组。 – lmsteffan 2013-04-07 10:19:52

+0

@lmsteffan你其实是对的,我现在对自己感到困惑。这似乎是我的描述适合,但实际上,应该没有空位。 – jAndy 2013-04-07 10:21:51

0

问题真的与你没有使用连续索引,而不是事实,你正在使用的流行功能的事实。您会注意到,在第一个长度的打印中,数组的长度是7,尽管数组中只有3个项目。这与长度正在返回最大索引/属性(+1)的事实有关,因为其余的值被设置为未定义的值。

你真的有去与非顺序索引?如果是这样,你可能想尝试和使用:

var counter = 0; 
for (var i in a) { 
    counter++; 
    print("Property: "+i); 
} 
print("Total items: "+counter); 

但是,这远非最佳,性能明智。

+0

你好,我没有任何问题的代码。这是纯粹的人工构造,因为我只是试图理解语言。我正在寻找解释,为什么它这样工作,而不是如何解决它 – 2013-04-07 10:25:27

+0

得到你。然后,我必须同意上面的答案,但我不确定所有浏览器中的相同行为是否相同。 – sagibb 2013-04-07 10:35:58

1

“数组的长度被计算为所有 属性的最大数值”

这不是准确的阵列的所有用途。如果您为数组中的某个索引分配一个值,那么它的工作方式就是这样,但如果您专门设置了length或者使用了诸如pop之类的方法,则不会这样。

例子:

var a = []; 
a.length = 5; 

console.log("length =", a.length); 

for (var i = 0; i < a.length; i++) 
    console.log("a.hasOwnProperty(", i, ") =", a.hasOwnProperty(i)); 

输出:

length = 5 
a.hasOwnProperty(0) = false 
a.hasOwnProperty(1) = false 
a.hasOwnProperty(2) = false 
a.hasOwnProperty(3) = false 
a.hasOwnProperty(4) = false 

现在你有没有任何元素的数组,但长度为5

+0

但问题仍然存在,为什么和在哪里成为'undefined'值的插槽'1 ... 4' * real *插槽?实际上,正如@lamsteffan指出的那样,我们只是处理一个稀疏数组。 – jAndy 2013-04-07 10:31:30

+0

@jAndy我猜Guffa是对的。 'Array.splice'和'length'的直接赋值显示了相同的行为,其原因似乎是'length'在某个时刻被赋值。 – 2013-04-07 10:33:54

+0

@jAndy:未使用的插槽没有任何值,但是如果尝试从不存在的插槽中读取,则会返回“undefined”。例如'console.log([] [42]);'显示'未定义'。 – Guffa 2013-04-07 10:40:34