iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 17
1
Day 17

頭和腳的關係如此微妙,一個思考一個執行,但對程式的陣列來說,都只是陣列的一部分而已,很公平。

接下來我們會分兩天,聊聊從陣列的開頭(前面)新增或刪除陣列元素的方法。

unshift()shift()這一對,說穿了和push()pop()ㄧ樣,只是一個從陣列的前頭增加與刪除元素,另一個則是從陣列的尾端操作。
https://ithelp.ithome.com.tw/upload/images/20191002/20104175DIqBdswLxB.png

這是我們從操作面來看的不同,要再探討深一點,就必須了解這兩對寶,在記憶體的操作方式也就是資料結構還是有很大的不同。前一篇我們有介紹到資料結構的堆疊(Stack)和佇列(Queue),從尾部增加和刪除元素的push()pop()是以堆疊(Stack)「後進先出 LIFO」的方式記憶,而從陣列前頭的unshift()shift()的儲存則是採用佇列(Queue)「先進先出 FIFO」的資料結構。
我們再來以此圖複習一下:

https://ithelp.ithome.com.tw/upload/images/20191002/2010417512XaDyfODV.png

unshift() 頭上頂著好幾塊餅的非洲婦女

使用unshift()陣列方法,可將一個或多個一組的元素,從陣列的前端加入。也因為是從開端加入元素,連帶也會變動到所有元素的索引值(index),最後被加入陣列的元素索引值,永遠都是index[0],如果是以多個元素一組的方式加入,則是第一個元素的索引值是 0 。

Array.prototype.unshift() - JavaScript | MDN

原型: Array.prototype.unshift()
功能: 會添加一個或多個元素至陣列的開頭,並且回傳陣列的新長度。
改變: 原陣列會改變
語法: arr.unshift(element1[, ...[, elementN]])
回傳值: 呼叫此方法之物件的新 length 屬性值。
參數: elementN 欲添加至陣列開頭的元素。

https://ithelp.ithome.com.tw/upload/images/20191002/20104175rxy2OArQNk.png

我們先來看一下操作方式:

const arr = [1,2,3,4,5]
arr.unshift(0); // 6
arr; // [0, 1, 2, 3, 4, 5]

arr.unshift(-1,0); // 8
arr; // [-1, 0, 0, 1, 2, 3, 4, 5]

arr.unshift(['Hello','Wow']); // 9
arr; // [Array(2), -1, 0, 0, 1, 2, 3, 4, 5]

當我們查閱arr時會,我們可以觀察到,一整個陣列被當作是一個元素加入。

https://ithelp.ithome.com.tw/upload/images/20191002/20104175HbWEcAZu28.png

如果想要一次加入多個元素,都要以逗號做區隔,索引值也會以逗號分隔的數量來增加。

需要注意的是unshift()會將我們所放在unshift()裡的引數列(argument list)unshift(引數列),以「一次性的」加入陣列的前端,而不會「一個個」的多次放入陣列裡,所以需要注意放入後的順序問題。假如元素是「逐次」的放入陣列前端,那麼這些加入的元素順序就會是倒過來的。

unshift() 是怎麼被寫出來的?

前面有提到unshift()可以ㄧ次或多個元素一起新增至陣列中,所以比較方便的是也把這些引數放在一個陣列裡處理。
我們可以使用其餘參數(rest parameter)的功能,其餘參數會將一個不確定數量的參數,集合在一個陣列中。且unshift()的回傳值是返回處理過的陣列長度,這點只要使用陣列的屬性length就可拿到,接下來怎麼把引數的內容一一放到陣列前頭呢?

我們先來直接看一下 code:

Array.prototype.unshift2 = function ( ...elements ) {
    for ( let i = this.length + ( elements.length - 1 ); i >= 0; i-- ) {
    this[ i ] = this[ i - ( elements.length ) ];
    }
    for ( var i = 0; i < elements.length; i++ ) {
        this[ i ] = elements[ i ];
    }
    return this.length;
}

const arr =[1, 2, 3];
arr.unshift2(4, 5, 6);

第一個迴圈,我們把i設為原陣列的長度+引數長度-1,條件為i >= 0;,每跑一次i就減 1。
用此方式去偵測原陣列和引數 elements 的長度,再把引數長度先空出來。

也就是指定引數的索引值,給空出來的原陣列索引值。
整理一下:this -> let arr = [1, 2, 3];
第一個 for(i=3+2 -> 5; i >= 0; i--)
第一圈 this[5] = this[5-(3)=2] 5--  -> i = 4
第二圈 this[4] = this[4-(3)=1] 4--  -> i = 3
第三圈 this[3] = this[3-(3)=0] 3--  -> i = 2
第四圈 this[2] = this[2-(3)=-1] 2--  -> i = 1
第五圈 this[1] = this[1-(3)=-2] 1--  -> i = 0
第六圈 this[0] = this[0-(3)=-3] 0--  -> i = 0   >=0 終止

這時的 this -> [undefined, undefined, undefined, 1, 2, 3]

第二個迴圈負責把要增加的元素(引數),一一指定給第一個迴圈先空下來的引數數量空隙。

第二個 for(i=0; i < 3; i++)
第一圈 this[0] = elements[0]
第二圈 this[1] = elements[1]
第三圈 this[2] = elements[2]

這個迴圈主要是把引數陣列裡的index 對應到第一個迴圈空出來的index裡,只要對應到 index 也表示會對應到值。

最後,再把整個陣列長度回傳出來。就完成了!

本人實在不太會解說整個程式的流程 弱到趴糞,所以把迴圈的部份寫出來,這也是我們在觀察其他人寫的程式碼的方法之一。
希望有幫助到大家 自己也受益

明天就來點單純的shift()小菜囉~

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


上一篇
JS 從陣列 Array 尾端刪除元素的 pop()
下一篇
JS 從陣列 Array 的開頭刪除元素
系列文
JavaScript之一定要了解的 Array 與方法34
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言