Day 05
一列隊伍有長度,也有各式各樣不同的物種,這才有趣嘛!
length 這個屬性應該算是我們在學 Javascript 的初期,最早開始用的一個屬性,我們常常來用它來當作是跑字串或陣列的迴圈條件,但是,作為 Array 的唯一屬性 length 真的有這麼單純嗎?
我們可以從 Chrome 的開發工具的 console 裡,輸入window.Array.prototype
可以找到它。並試著了解他多一點。
先看一下 NDM 對它的定義:
作為 Array 類型的實例物件的 length 屬性,設置或回傳該陣列中的元素數。 該值是一個無符號的 32 位整數,其數值總是大於陣列中的最高索引。
嗯,解釋得很清楚,但好像單薄了點。果然,查找了「JavaScript 大全」的解釋,把 length 解釋得較為詳細,且還講到了密集陣列(dense)和稀疏陣列(sparse),其中更強調了無論是以上哪種型態的陣列,length 的長度不會等於或小於陣列的最大索引值,也就是說 length 會比陣列最大的索引值多 1。但有個例外,就是空陣列。 廢話
這個其實不難理解,在許多程式語言裡,陣列的索引值都是從 0 開始算起,當然 JavaScript 也不例外。JavaScript 的 length 是從 1 開始,從下面這張圖片可以看出為什麼長度總比索引值大的原因。
怎麼使用 length ?
別看 length 這個屬性,好像只能知道陣列的長度,但是如果知道怎麼活用它,會發現他的功用還不少。接下來介紹是幾種 length 的用法:
求陣列的長度
- 只要在我們想知道的陣列變數,以方法的方式加上
.length
。回傳回來的就是這個陣列的長度。 - 不管是密集或稀疏陣列,長度(length)永遠大於索引值(index)。
1 | let arr = ['hi', 'ho', 'woops', 'ciao']; |
- 如果重新指定長度,
.length
,原本有的會被刪除,沒有的會以空的補上而成為稀疏陣列。
1 | arr = [1, 2, 3, 4, 5]; |
把陣列清空 第一種
這的確是個快速清空的方法,但是陣列在 JavaScript 裡,骨子裡是物件,也就是在記憶體裡,當我們宣告它時,也同時記錄了它在記憶體的位置(call by reference),而如果我們複製了這個陣列,然後用 length 這個屬性去操控它,嗯,恩湯喔,很危險,同時會指向來源陣列,所以也會修改來源陣列。
這個 codepen 有更詳細的範例說明,記得只觀察比對 JS 和 console(在左下角)的部分。
1 | let say = ['hi', 'ho', 'woops', 'ciao']; |
把陣列清空 第二種
和第一種一樣,都會更動到來源陣列,請慎用。
1 | let say = ['hi', 'ho', 'woops', 'ciao']; |
把陣列最後一個元素抓出來
除了可以用 JavaScript 的內建函式 pop();
去提取陣列的最後一個元素外,還可以用下面這種方法。找到陣列中最後一個值, 把 length 的長度減掉 1 再把它對應到索引值,就是陣列的最後一個了。
1 | let say = ['hi', 'ho', 'woops', 'ciao']; |
刪除陣列的最後一個元素
直接把原本的陣列長度,用指派的方式減掉最後一個陣列元素。
1 | let say = ['hi', 'ho', 'woops', 'ciao']; |
從陣列尾部增加一個元素
如果要在陣列尾部增加一個元素,除了可以用 JavaScript 的內建函式 push();
去增加外,還可以用這種方法增加,真的很奇妙!
1 | let say = ['hi', 'ho', 'woops', 'ciao']; |
當作是迴圈的停止條件
這是我們常用的方法,把迴圈限制在陣列的長度範圍內,跑完陣列的長度自動停止,真的很方便。以下的範例就是計算陣列裡面元素的總和。
1 | let nbr = [2, 4, 6, 8]; |
服用 length 注意事項
雖然 length 可以這樣用,但並不表示就是好的方法,因為 length 是陣列的屬性,陣列在 JavaScript 是屬於非原始型別(Non-Primitive)也就是物件型別(Object type)與傳址(Pass by referance), 別緊張,這幾個名詞都是指同一件事情。 所以不可不慎用,一改動是會同時更動複製的原陣列的。
小總結
不知道這篇 length 的介紹,有沒有讓大家對它有另一種看法,程式的變化實在是太精采,但知道活用或許比知道原本的功能更重要吧?
透過鐵人賽寫文來查找資料,實在是個不錯的方法,人家說「當爸爸之後才學著怎麼當爸爸」,本人雖然無法當爸爸,但對這句話的涵義也頗有感觸,期望在這樣查找與發現的狀態下,多練些腦肌肉也是好的。
如有需要改進的地方,拜託懇求請告知,我會盡量快速度修改,感謝您~
==要補充==
陣列裡的 length 屬性
對稀疏陣列來說,如果.length 屬性比元素的數目還大,length 會比陣列索引還大,也就是說,陣列永遠不會有元素的索引大於或等於陣列的.length
長度。為了要為持這個不變式(invariant),陣列會有兩個特殊行為: 1.如果我們指定一個值給索引 i,而 i 大於或等於陣列目前的 length 長度,那麼 length 的屬性就會被設為 i+1。 2.如果我們將 length 屬性設為小於目前陣列值的非負整數 n,那麼,任何索引值大於或等於 n 的陣列元素都會因此從陣列中被刪除。
==記住:.length
長度永遠會比index[]
大 1,因為index
從 0 開始計算。==
1 | a = [1, 2, 3, 4, 5]; // 創建一個有五個元素的陣列 |
我們也可將長度射設成比現在更大的長度,但並不會因此新增任何的陣列元素,而是會在陣列尾部創建一塊稀疏的區域。
1 | a.length = 15; // a 變成 [empty × 15] |
可以把 length 設為唯讀,鎖死陣列長度嗎?可以。在 ECMAScript,我們可以使用 Object.defineProperty()把陣列 length 設為唯讀,這樣不只無法更改長度,也無法增加長度與刪除。
1 | a = [1, 2, 3, 4, 5]; // |
節錄「JavaScript 大全」的說明:
- 陣列(Array)是動態的(dynamic):陣列的長度可以根據需求變長或變短,沒有必要在創建陣列時,宣告陣列的長度,或是在長短改變時重新配置(reallocate)。
- 每個陣列都有一個控制或偵測的屬性:length 特性,對非稀疏陣列(nonsparse)來說,length 代表陣列中所包含的元素數量
對稀疏陣列(sparse)而言,length 比陣列中所有元素的索引值還要大,原因不難理解,因為索引值是從 0 開始計算,而 length 是從 1 開始。
1 | // 陣列常値 |
length 的妙用
數組的 length 不是只讀的。所以我們可以通過 length 完成
【1】從數組末尾移除項
【2】在數組末尾添加新項
【3】清空數組
/*\
_ 從數組末尾移除項
_ **/
var colors = [“red”, “blue”, “green”]; // 創建一個包含 3 個字符串的數組
colors.length = 2;
alert(colors[2]); // undefined
/***
* 在數組末尾添加新項
* **/
var colors = ["red", "blue", "green"]; // 創建一個包含3個字符串的數組
colors[colors.length] = "black"; // (在位置3)添加一種顏色
colors[colors.length] = "brown"; // (在位置4)再添加一種顏色
/***
* 清空數組
* **/
var colors = ["red", "blue", "green"]; // 創建一個包含3個字符串的數組
colors.length = 0;
console.log(colors); // []
圖篇來源:
https://unsplash.com/s/photos/seat
真清除 尾巴斷了
length 除了可以拿來查看陣列的長短,還可以拿來刪除陣列尾部的元素。只要直接指定想要的長度,截至想保留的長度,就可以輕鬆刪掉尾部的元素了。
1 | let a = [1, 2, 3, 4, 5, 6, 7, 8, 9]; |