0%

如何把陣列或元素清空和刪除

Day 10

好好的吃頓飯也是一種優雅。刪除也是。

「如何把陣列或元素清空」也要寫一篇? 妳當牛肉麵在寫嗎?
自從有了這本「JavaScript 大全」當枕頭,阿不是,才發現自己真是懵懂無知,但求知識不嫌遲,只能盡量腦補,讓自己盡量處於知道 JavaScript 到底做了什麼的狀態~結論是:路,還很長。

原本以為 Javascript 像某些語言ㄧ樣,可以控制記憶體或把某部分的記憶體釋放出來,就在網路上開始找如何刪除變數的文章,結果搜尋結果清一色是在講,如何「刪除陣列裡的元素」這件事,才發現 JavaScript 似乎沒有完全把變數刪除這件事,我們也看不見記憶體的存取或清空的狀態,只能用一些機制來驗證。結論是對陣列 Array 來說,沒有把陣列刪除變數這件事,似乎就只能把陣列清空,而不能刪除變數。 自己無法作主的人生

用 Delete 刪除陣列可以嗎?

在「JavaScript 大全」裡 p55 有說明: 1.如果用let 來宣告變數,創立的特性會是nonconfigurable也就是不可配置的,這個變數是不可用delete這個運算子刪除。 2.如果不是在strict模式底下,將值指定給一個為宣告的變數,JavaScript 會自動為我們創建一個全域變數,用這種方式創建的變數具有configurable特性,也就是可以被delete運算子刪除。

第一點說的宣告,其實也包括了用letconst來宣告變數,我們可以可以用簡單的方式來測試一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let a = 42;
delete a; // false
console.log(a); // 42

let b = 42;
delete b; // false
console.log(b); // 42

const c = 42;
delete c; // false
console.log(c); // 42

d = 42;
delete d; // true
console.log(d); // Uncaught ReferenceError: d is not defined

變數 d 就真的這樣被刪除掉了!

那麼其他不是透過Delete刪除的變數,是怎麼被全域環境清除掉的?
JavaScript 有一種清理 廚餘的機制,是一種垃圾收集器(garbage collector),它會在變數不再被使用的時候出現,並釋放掉不再使用的記憶體,當然,變數也就這樣真的刪除掉了。

終於要進入今天的主題了:刪除陣列元素 在拖什麼啊

完全清空陣列

第一種方法 全部掏掉

將空陣列[]直接指派給要清除的 Array,這種方式其實不算清空,比較像是我們拿另一塊空的記憶體,重新指派給這個變數。

1
2
3
4
5
let arr1 = [1, 2, 3, 4, 5, 6];
let arr2 = arr1;
arr1 = [];
arr1; // []
arr2; // [1, 2, 3, 4, 5, 6]

可以確定的是,如果我們複製了一份,複製的那份將不會受到原陣列的影響。
這一種方式和底下幾種清除陣列元素的方式,有一個很大的不同,就是使用重新指派的方式清空陣列,如arr1 =[],因為重新指派,所以即使在這之前有做陣列複製如arr2 = arr1,兩個陣列也不會互相影響。
記憶體配置圖

第二種方法 將長度歸零就沒事?

直接將陣列的長度length0,這種方式效能會比較好。但是,恩湯恩湯。因為複製於這個陣列的其他陣列,也會被改變。也就是說是以參考同一個記憶體位置by Reference的方式進行複製。

1
2
3
4
5
6
let arr1 = [1, 2, 3, 4, 5, 6];
let arr2 = arr1;
arr1.length = 0;

arr1; // []
arr2; // []

第三種 用 splice 就比較好?

splice()通常是拿來刪除陣列裡的某個元素,當然也可以拿來刪除元素,但是 splice()本身並不會複製一份新陣列,而是會指向原陣列的位址,所以原陣列被刪除的元素,複製過來的陣列元素也同時會被刪除。
splice()的用法在後面的篇章會有更詳盡的介紹。

1
2
3
4
5
6
7
let arr1 = [1, 2, 3, 4, 5, 6];
let arr2 = arr1;
arr1; // [1, 2, 3, 4, 5, 6]
arr1.splice(0, arr1.length);

arr1; // []
arr2; // []

第四種 趕盡殺絕的清

利用while 迴圈與陣列長度,使用pop()從尾端刪除陣列元素的功能遍歷陣列,一一從尾端清除陣列元素,pop()同樣是就地改變的方法,所以也會同時改動到被複製出來的陣列。我們在前幾章有講到控制陣列長度的特有屬性:Length,有興趣的可以參考一下。

1
2
3
4
5
6
7
8
9
let arr1 = [1, 2, 3, 4, 5, 6];
let arr2 = arr1;
arr1; // [1, 2, 3, 4, 5, 6]
while (arr1.length) {
arr1.pop();
}

arr1; // []
arr2; // []

以上三種方法,都是在複製陣列時,以參考同一個記憶體位置by Reference的方式進行複製,所以使用arr1.length = 0的方式清空陣列,則所複製出來的陣列arr2 = arr1arr2會受原來的arr1影響,同時被清空,所以將arr1.length = 0也等於將arr2清空。

Delete 的另一種用法:將陣列某一元素清除

Delete 的假清除 洞還在

在文章最初,我們介紹了用delete運算子來刪除整個陣列,但其實它比較常被拿來清除陣列的某一元素。直接清除陣列元素的方法delete,個人覺得這也不算真的清除,只是把這個元素回歸為空的狀態,也就是 empty(undefined)。我們可以以length來驗證陣列元素並不會因為使用delete而改變長度。

1
2
3
4
5
6
7
let arr1 = [1, 2, 3, 4, 5];
arr1.length; // 5 -> arr1 陣列的長度
delete arr1[1]; // true -> 刪除索引值為1的元素
arr1; // [1, empty, 3, 4, 5] -> 被刪除的元素變成 empty 空的了。
arr1.length; // 5 -> arr1 陣列的長度仍是5
1 in arr1; // false -> 確認索引值 1 在 arr1 陣列裡有沒有值
arr1[1] = 2; // 將 2 指定給剛剛刪除的索引值 1

刪除陣列的元素,類似將undefined指定給該元素,但仍和empty會有些微差距嘛?這點還需要驗證。要特別注意的是,用delete刪元素並不會改變陣列的長度,且此陣列就成為一個「稀疏」的陣列。

使用「稀疏」陣列會造成什麼影響?有時候我們希望用一些方法來處理陣列,然後把處理完的結果回傳回來,如果陣列裡有稀疏的狀態,那麼當我麼用方法去遍歷陣列元素時,就會回傳 undefined

1
2
3
4
5
6
7
let arr1 = [1, 2, 3, 4, 5];
delete arr1[1]; // 刪除某一元素陣列後的陣列 -> [1, empty, 3, 4, 5]

let arr2 = arr1.map(function(x) {
return x * 2;
}); // 用 map() 遍歷每個元素將其 * 2
arr2; // 回傳結果 -> [2, empty, 6, 8, 10]

把無所事事的傢伙通通踢出去

有時候我們會拿到有許多無效 被搞爛的元素在陣列裡,如何刪除陣列裡這些無所事事的undefinednull0或其他的元素?讓處理陣列資料時更順利?我們可以利用 JavaScript 的while迴圈,來遍歷陣列內容,一一來把我們過濾過後,要保留的元素留在陣列中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function filter_array(testArray) {
let index = -1,
arrLength = testArray ? testArray.length : 0,
resIndex = -1,
result = [];

while (++index < arrLength) {
let value = testArray[index];

if (
value != null &&
value !== '' &&
value !== undefined &&
!isNaN(value) &&
value !== false &&
value !== 0
) {
result[++resIndex] = value;
}
}

return result;
}
filter_array([NaN, 0, 15, false, -22, '', undefined, 47, null]); // [15, -22, 47]

相信大家在看完這一篇之後,會對於刪除陣列或元素有更加深的認識。老實說,真心覺得鐵人賽最大的收穫,是在寫文章的時候,找到的資料有吸收,且發現原來這麼多方法與面向,真的是一件很有趣的事啊! 且前幾天收到一些大大的回饋,無論是指定或提問,都讓本人雀躍不已,在每一次的交流中,更可以加深自己對 JavaScript 的理解,實在感謝!

如有需要改進的地方,拜託懇求請告知,我會盡量快速度修改,感謝您~