iT邦幫忙

第 12 屆 iThome 鐵人賽

0
Modern Web

從技術文章深入學習 JavaScript系列 第 28

Day 28 [整理03] JavaScript類數組

  • 分享至 

  • twitterImage
  •  

甚麼是類數組

先來打造一個很酷的數組

let obj = {
  '0': 'a',
  '1': 'b',
  '2': 'c',
  'length': 3,
  'push': Array.prototype.push
}
console.log(obj);

https://ithelp.ithome.com.tw/upload/images/20210201/20124350YgW9pNEjWB.png

乍看之下他還只是一個平常的對象,但其實這個對象這時候已經變成一個類數組了!

我們來對他做以下操作可以更明白

https://ithelp.ithome.com.tw/upload/images/20210201/20124350nuCIVlxBK7.png

可以發現到這時候他多了一個 3: "d" ,對象原本是不能這樣做的,但是在這邊卻可以實現,因此才對他取名叫做類數組。

如何打造

要打造出一個類數組有幾個條件

  1. 他必須要是一個對象
  2. 屬性要為索引(數字)值
  3. 一定要有length存在
  4. 最好可以加push

附註:

如果想讓它變得更像數組可以加上splice,如下圖

https://ithelp.ithome.com.tw/upload/images/20210201/20124350AXpzr50iPi.png

來一個比較難問題

let obj = {
  '2': 'c',
  '3': 'd',
  'length': 3,
  'push': Array.prototype.push,
};

obj.push('f')
obj.push('g')

console.log(obj);

大家先別看答案,先想想看這個東西打印出來會長怎樣

答案

https://ithelp.ithome.com.tw/upload/images/20210201/20124350L0C2c0A6s6.png

分析

3的 "d" 居然被 "f" 覆蓋掉了,而且多了一個4 : "g" ,我們來講解一下實現原理!!

先來看看 Array.prototype.push 源碼

擷取自

https://www.jianshu.com/p/85d1ec72a140

function ArrayPush () {
  var n = TO_UNIT32(this.length); // 被push數組的長度(類數組採用的length就是這個!)
  var m = %_ArgumentsLength(); // push的總長度
  for (var i = 0; i < m; i++) {
    this[i + n ] = %_Arguments(i); // 複製給原數組
  }
  this.length = n + m; // 修正最終數組長度
  return this.length;
}

從第2行可以得知為甚麼Obj一定要有length

再來第4到6行就能知道他push的觀點全是在length上

也就是說在obj對象最該觀察的不是其他元素而是length!

再來看看原題目

let obj = {
  '2': 'c',
  '3': 'd',
  'length': 3,
  'push': Array.prototype.push,
};

obj.push('f')
obj.push('g')

console.log(obj);

到這邊就很明瞭為甚麼 3會變f 而 4會變g,原因全在

https://ithelp.ithome.com.tw/upload/images/20210201/20124350oRFEw1lNdT.png

思路

​ 大家可以想一下i = 0 的情況下會發生甚麼事,是不是this[0 + n]會被push的第一個元素取代,那這裡他的n代表的不就是Obj的 length

​ 就表示說Obj [3] 會被 f 取代,並且length變4 ,然後Obj[4]再被 g取代,length變5!這就是這題的實現原理。


上一篇
Day 27 [其他05] 前端必知必会--操作URL的黑科技
下一篇
Day 30 [分享] 學習 JavaScript 的優秀資源
系列文
從技術文章深入學習 JavaScript29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言