簡體   English   中英

數組長度和未定義的索引

[英]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))等於PToUint32(P)不等於2 32 -1時,屬性名P (以String值的形式)是數組索引。

因此,在您的情況下, 24是有效索引,但在數組中只定義了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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM