[英]Array length and undefined indexes
我只是想了解Javascript數組是如何工作的,但我在這里遇到了一個復雜的問題。
首先我創建了我的數組:
var arr = [];
並在其中設置一些元素:
arr[5] = "a thing";
arr[2] = undefined;
我認為我應該有一個大小為2的數組,因為我在2個特定索引上只有兩個對象。 所以我用數組的.length
屬性測試它:
document.write(arr.length + "<br>");
有趣的是,結果是6.但它必須包含兩個項目。 它的大小怎么樣? 它可能與我使用的最新指數有關,這里arr[5] = "a thing";
然后我試圖循環它:
var size = 0;
for(var x in arr){
size++;
}
而size
變量現在是2.所以,我從中學到了:如果我使用for in
循環,我將計算其中有多少屬性,而不是它的最后一個索引。
但是如果我嘗試使用document.write(arr[4])
(尚未設置),它會寫入undefined
。
那么為什么arr[2]
計算在for..in
循環中,而不是arr[4]
?
讓我回答一下我的問題:我在想什么類型typeof undefined == undefined
這是非常真實的。 但這是JavaScript,我們需要使用自己的規則來玩它:)
jsFiddle和片段如下。
var arr = []; arr[5] = "a thing"; arr[2] = undefined; document.write(arr.length + "<br>"); var size = 0; for(var x in arr){ size++; } document.write(size + "<br>"); document.write(arr[4] + "<br>");
注意:數組索引只是Array對象的屬性。
引用MDN的length
和數值屬性部分之間的關系 ,
當屬性是有效的數組索引並且該索引超出數組的當前邊界時,在JavaScript數組上設置屬性時,引擎將相應地更新數組的
length
屬性。
引用ECMA腳本5 數組對象的規范,
每當添加名稱為數組索引的屬性時,如果需要,將更改length屬性,使其大於該數組索引的數值 ; 每當更改length屬性時,將自動刪除名稱為數值索引且值不小於新長度的每個屬性
因此,當您在索引5
處設置值時,JavaScript引擎會將Array的長度調整為6
。
引用ECMA腳本5 數組對象的規范,
當且僅當
ToString(ToUint32(P))
等於P
且ToUint32(P)
不等於2 32 -1時,屬性名P
(以String值的形式)是數組索引。
因此,在您的情況下, 2
和4
是有效索引,但在數組中只定義了2
。 你可以這樣確認
arr.hasOwnProperty(2)
其他索引尚未在數組中定義。 因此,您的數組對象稱為稀疏數組對象 。
那么為什么arr [2]被計入for..in循環而不是arr [4]不算?
for..in
枚舉對象的所有有效可枚舉屬性。 在您的情況下,由於數組中只有2
是有效屬性,因此將對其進行計數。
但是,當您打印arr[4]
,它會打印undefined
,因為如果您嘗試訪問未在對象中定義的屬性,JavaScript將返回undefined
。 例如,
console.log({}['name']);
// undefined
類似地,由於arr
尚未定義4
,因此返回undefined
。
雖然我們是關於這個主題的,但您也可能想要閱讀這些答案,
具有undefined
值的屬性與不存在的屬性之間存在差異,此處使用in
運算符說明:
var obj = {
one: undefined
};
console.log(obj.one === undefined); // true
console.log(obj.two === undefined); // true
console.log('one' in obj); // true
console.log('two' in obj); // false
當您嘗試獲取不存在的屬性的值時,仍然會undefined
,但這不會使其存在。
最后,為了解釋你看到的行為: for in
循環只會遍歷那個鍵in
對象中的鍵(並且是可枚舉的)。
同時,如果該索引大於或等於當前長度,則僅將length
調整為比指定的索引多一個。
要從數組中刪除undefined
值,請嘗試使用.filter()
var arr = []; arr[5] = "a thing"; arr[2] = undefined; arr = arr.filter(Boolean); document.write(arr.length);
這一切都歸結為如何通過機器處理空間。 讓我們從最簡單的想法開始:
var arr =[];
這反過來又創造了,你現在可以存儲信息的位置 。 正如@Mike'Pomax'Kamermans指出的那樣:這個位置是一個特殊的javascript對象,它反過來作為鍵和值的集合,如下所示:
arr[key] = value;
現在繼續你的代碼:
arr[5] = "a thing";
機器現在知道你正在創建第6個位置 / 第5個鍵的值(給出值)(因為數組的第一個位置是0)。 所以你結束了這樣的事情:
arr[,,,,,"a thing"];
這些逗號代表數組中的空位(@RobG指出的符號)。
當你聲明時,會發生同樣的事情:
arr[2] = undefined;
arr[,,undefined,,,"a thing"];
因此,當您使用“for var in”在數組內部進行迭代時,您將檢查此數組中已填充的每個空格,因此依次為2。
不同的是,當您檢查數組的長度時,您正在查看數組內部存儲信息的空間數 ,而后者又是6。
最后,javascript將數組中的空房間解釋為未識別的值,這就是arr [4]被輸出的原因。
希望能回答你的問題。
JavaScript數組(至少在第一個版本中)是具有length
屬性的普通對象。 你經歷的大多數奇怪的行為都是這樣的結果。
結果有趣,它是6.但它必須包含兩個數據,它的大小如何可以是6? 它可能與我在這里使用的最新索引有關[5] =“一件事”;
它導致6
因為length
總是比最高索引高1,即使數組中的項目實際上更少。
o為什么arr [2]被計入for..in循環而不是arr [4]不算?
因為你在做的時候:
arr[2] = undefined;
實際上,您正在向數組對象添加一個名為2
的鍵。 結果,值arr[2]
在for in
循環中計數,而a[4]
被忽略。
賦值設置數組的屬性,因此當您for var i in
for循環中執行for var i in
,只能看到已設置的屬性(即使您將它們設置為未定義)。 當你分配一個新的integery屬性,比如arr[6]
,數組會將數組的長度修改為7.數組中的內存可能會或者可能不會相應地重新分配,但是當你去使用它時它會在那里它 - 除非你的系統內存不足。
根據RobG對ECMA-262所說的評論進行了編輯。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.