iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 5
1
Day 5

一列隊伍有長度,也有各式各樣不同的物種,這才有趣嘛!

length 這個屬性應該算是我們在學 Javascript 的初期,最早開始用的一個屬性,我們常常來用它來當作是跑字串或陣列的迴圈條件,但是,作為 Array 的唯一屬性 length 真的有這麼單純嗎?

我們可以從 Chrome 的開發工具的 console 裡,輸入window.Array.prototype 可以找到它。並試著了解它多一點。
https://ithelp.ithome.com.tw/upload/images/20190920/20104175pYv5vEp0S7.png

先看一下 MDN 對它的定義:

作為 Array 類型的實例物件的 length 屬性,設置或回傳該陣列中的元素數。 該值是一個無符號的32位整數,其數值總是大於陣列中的最高索引。

嗯,解釋得很清楚,但好像單薄了點。果然,查找了「JavaScript 大全」的解釋,把 length 解釋得較為詳細,且還講到了密集陣列(dense)和稀疏陣列(sparse),其中更強調了無論是以上哪種型態的陣列,length 的長度不會等於或小於陣列的最大索引值,也就是說 length 會比陣列最大的索引值多 1。但有個例外,就是空陣列。 廢話

這個其實不難理解,在許多程式語言裡,陣列的索引值都是從 0 開始算起,當然 JavaScript 也不例外。JavaScript 的 length 是從 1 開始,從下面這張圖片可以看出為什麼長度總比索引值大的原因。

https://ithelp.ithome.com.tw/upload/images/20190920/20104175qoUWcKEF56.png

怎麼使用 length ?

別看 length 這個屬性,好像只能知道陣列的長度,但是如果知道怎麼活用它,會發現它的功用還不少。接下來介紹是幾種 length 的用法:

求陣列的長度

只要在我們想知道的陣列變數,以方法的方式加上.length。回傳回來的就是這個陣列的長度。

let arr = ["hi","ho","woops","ciao"];
console.log(arr.length); // 4

把陣列清空

這的確是個快速清空的方法,但是陣列在 JavaScript 裡,骨子裡是物件,也就是在記憶體裡,當我們宣告它時,也同時記錄了它在記憶體的位置(call by reference),而如果我們複製了這個陣列,然後用 length 這個屬性去操控它,嗯,恩湯喔,很危險,同時會指向來源陣列,所以也會修改來源陣列。
這個codepen 有更詳細的範例說明,記得只觀察比對 JS 和 console(在左下角)的部分。

let say = ["hi","ho","woops","ciao"];
say.length = 0;
console.log(say) // []

上面範例中的say.length = 0; 也可以用say.length = [];取代,效果一樣,原因是 JavaScript 會把[]轉成數字型別的0

Number([]) // 0

把陣列最後一個元素抓出來

除了可以用 JavaScript 的內建函式 pop();去提取陣列的最後一個元素外,還可以用下面這種方法。找到陣列中最後一個值, 把 length 的長度減掉 1 再把它對應到索引值,就是陣列的最後一個了。

let say = ["hi","ho","woops","ciao"];
let lastSay = say[say.length-1];
console.log(lastSay) // ciao

刪除陣列的最後一個元素

直接把原本的陣列長度,用指派的方式減掉最後一個陣列元素。

let say = ["hi","ho","woops","ciao"];
say.length = say.length-1;
console.log(say) // ["hi", "ho", "woops"]

從陣列尾部增加一個元素

如果要在陣列尾部增加一個元素,除了可以用 JavaScript 的內建函式 push();去增加外,還可以用這種方法增加,真的很奇妙!

let say = ["hi","ho","woops","ciao"];
say[say.length] = "haha";
console.log(say) // ["hi", "ho", "woops", "ciao", "haha"]

當作是迴圈的停止條件

這是我們常用的方法,把迴圈限制在陣列的長度範圍內,跑完陣列的長度自動停止,真的很方便。以下的範例就是計算陣列裡面元素的總和。

let nbr = [2, 4, 6, 8];
let sum = 0
for (let i = 0; i < nbr.length; i++) {
    sum = sum + nbr[i];
}
console.log(sum) // 20

服用 length 注意事項

雖然 length 可以這樣用,但並不表示就是好的方法,因為 length 是陣列的屬性,陣列在 JavaScript 是屬於非原始型別(Non-Primitive)也就是物件型別(Object type)與傳址(Pass by referance), 別緊張,這幾個名詞都是指同一件事情。 所以不可不慎用,一改動是會同時更動複製的原陣列的。

小總結

不知道這篇 length 的介紹,有沒有讓大家對它有另一種看法,程式的變化實在是太精采,但知道活用或許比知道原本的功能更重要吧?

透過鐵人賽寫文來查找資料,實在是個不錯的方法,人家說「當爸爸之後才學著怎麼當爸爸」,本人雖然無法當爸爸,但對這句話的涵義也頗有感觸,期望在這樣查找與發現的狀態下,多練些腦肌肉也是好的。

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


上一篇
JS 創建與宣告陣列 Array
下一篇
JS 陣列 Array 有哪幾種?
系列文
JavaScript之一定要了解的 Array 與方法34

2 則留言

0
huli
iT邦新手 5 級 ‧ 2019-09-20 15:55:13

先看一下 NDM 對它的定義 => MDN

把陣列清空第二種的部分,猜測你應該是想說:say = []; 而不是 say.length = [];,因為後者其實就跟第一種一樣

看更多先前的回應...收起先前的回應...
tsuifei iT邦新手 5 級 ‧ 2019-09-20 17:08:03 檢舉

歐~胡大,感謝,我的文字顛倒正又犯了,已改正。

say = [];say.length = []; 看似結果一樣,但應該是不一樣,要有複製才看得出來。其實我也很疑惑,JS 也接受say.length = [];這樣的寫法。

我做實驗的結果(下面這個範例的第三個)
https://codepen.io/tsuifei/pen/zYOMRKa?editors=0012
say = []會將一個新陣列重新指派給say
但是say.length = []; 會把原本依樣位址的資料清空,但是因為是指向同一個位址,所以如果從say複製過來的也會清空。

不知道我有沒有理解錯誤....

huli iT邦新手 5 級 ‧ 2019-09-20 17:25:09 檢舉

我說的一樣指的是 say.length = []; 跟「文章裡面提的第一種」say.length = 0; 一樣,我猜 JS 最終會把 [] 轉型成 0 之類的(不確定,純猜測),所以我才說一樣。

所以我才說你文章裡面提的這兩種其實是一樣的,原理都是把 length 設定成 0。然後想說會不會你第二種想提的其實是 say = []; 只是打錯程式碼。

tsuifei iT邦新手 5 級 ‧ 2019-09-20 17:31:12 檢舉

啊~了解,那我來改一下,
我們家ruru找了大全來看,在P46有寫型別轉換,的確剛剛測試Number([])會回傳 0 耶~

看完這篇真的收穫滿滿 ❤

tsuifei iT邦新手 5 級 ‧ 2019-09-20 21:25:29 檢舉

@ Ruru 好險妳在我旁邊讓我問,我們一起來把大全用爛吧,哈哈!

0
letter liu
iT邦新手 5 級 ‧ 2019-09-20 21:04:25

寫得很棒!

tsuifei iT邦新手 5 級 ‧ 2019-09-20 21:23:23 檢舉

Letter 謝謝你的稱讚,沒有和你們一起學習,我應該寫不出來的.....哭哭

我要留言

立即登入留言