點燈坊

失くすものさえない今が強くなるチャンスよ

使用 slice() 取得部份 Array

Sam Xiao's Avatar 2020-01-29

ECMAScript 的 Array.prototype 亦提供 slice() 取得部分 Array,也可套用在 Array-like object。

Imperative

let data = [1, 2, 3, 4, 5]

let slice = begin => end => arr => {
  let result = []

  for(let i = 0; i < arr.length; i++)
    if (i >= begin && i < end)
      result.push(arr[i])

  return result
};

slice(1)(3)(data) // ?

Imperative 會先建立欲回傳的 result array,使用 for loop 搭配 if 判斷,若 index 在傳進的 beginend 之中,則塞進 result 中。

slice000

slice()

let data = [1, 2, 3, 4, 5]

data.slice(1, 3) // ?

ECMAScript 原生的 Array.prototype 已內建 slice(),可直接使用。

arr.slice([begin[, end]])
取得部分 array

begin:array 的起始 index

end:array 的結束 index (但不包含)

slice001

let data = [1, 2, 3, 4, 5]

data.slice(1, -2) // ?

Index 也可以傳入負數,其中 -1 就是最後一個 element,-2 就是倒數第二個 element,以此類推。

slice002

let data = [1, 2, 3, 4, 5]

data.slice() // ?

slice() 不提供任何 argument,則相當於 shallow copy 完整 array。

slice003

Array-like object

let fn = function() {
  return Array.prototype.slice.call(arguments, 1, 3)
}

fn(1, 2, 3, 4, 5) // ?

透過 Array.prototype.slice().call()slice() 也可套用在 array-like object。

只有 function declaration 與 function expression 可用 arguments,arrow function 不行

slice004

let fn = function() {
  return [].slice.call(arguments, 1, 3)
}

fn(1, 2, 3, 4, 5) // ?

[]slice() 繼承自 Array.prototype,故也可用 [].slice() 取代之。

slice005

let _slice = Array.prototype.slice
let slice = Function.prototype.call.bind(_slice)

let fn = function() {
  return slice(arguments, 1, 3)
}

fn(1, 2, 3, 4, 5) // ?

Function.prototype.call() 可將 argument 傳給 function 執行,但此時 this 指向 function 為 undefined,需透過 bind()Array.prototype.slice 傳進產生新 function。

此為 ECMAScript 由 method 轉 function 慣用手法

slice006

let slice = (_ => {}).call.bind([].slice)

let fn = function() {
  return slice(arguments, 1, 3)
}

fn(1, 2, 3, 4, 5) // ?

Function.prototype 亦可使用 (_ => {}) arrow function 取代,而 Array.prototype 則以 [] 取代。

slice007

Conclusion

  • slice() 是真的 copy array,唯 ECMAScript 都是 shallow copy
  • Array-like object 透過 Array.prototype.[method].call() 借用 method 乃 ECMAScript 慣用手法
  • 藉由 Function.prototype.call.bind() 將 method 轉 function 亦為 ECMAScript 慣用手法

Reference

MDN, Array.prototype.slice()