2013-04-07 83 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