頭和腳的關係如此微妙,一個思考一個執行,但對程式的陣列來說,都只是陣列的一部分而已,很公平。
接下來我們會分兩天,聊聊從陣列的開頭(前面)新增或刪除陣列元素的方法。
unshift()
和shift()
這一對,說穿了和push()
、pop()
ㄧ樣,只是一個從陣列的前頭增加與刪除元素,另一個則是從陣列的尾端操作。
這是我們從操作面來看的不同,要再探討深一點,就必須了解這兩對寶,在記憶體的操作方式也就是資料結構還是有很大的不同。前一篇我們有介紹到資料結構的堆疊(Stack)和佇列(Queue),從尾部增加和刪除元素的push()
、pop()
是以堆疊(Stack)「後進先出 LIFO」的方式記憶,而從陣列前頭的unshift()
和shift()
的儲存則是採用佇列(Queue)「先進先出 FIFO」的資料結構。
我們再來以此圖複習一下:
使用unshift()
陣列方法,可將一個或多個一組的元素,從陣列的前端加入。也因為是從開端加入元素,連帶也會變動到所有元素的索引值(index),最後被加入陣列的元素索引值,永遠都是index[0]
,如果是以多個元素一組的方式加入,則是第一個元素的索引值是 0 。
Array.prototype.unshift() - JavaScript | MDN
原型: Array.prototype.unshift()
功能: 會添加一個或多個元素至陣列的開頭,並且回傳陣列的新長度。
改變: 原陣列會改變
語法: arr.unshift(element1[, ...[, elementN]])
回傳值: 呼叫此方法之物件的新 length 屬性值。
參數: elementN 欲添加至陣列開頭的元素。
我們先來看一下操作方式:
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
時會,我們可以觀察到,一整個陣列被當作是一個元素加入。
如果想要一次加入多個元素,都要以逗號做區隔,索引值也會以逗號分隔的數量來增加。
需要注意的是unshift()
會將我們所放在unshift()
裡的引數列(argument list)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()
小菜囉~
如有需要改進的地方,拜託懇求請告知,我會盡量快速度修改,感謝您~