Array.slice 8種不一樣用法

爲了保證的可讀性,本文采用意譯而非直譯。前端

想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等着你!git

JS數組slice方法是JS語言中最強大、最經常使用的內建函數之一。github

隨着React和其餘面向功能的JavaScript實踐的興起,它變得愈來愈重要,緣由有兩個:編程

  1. 函數式編程,尤爲是高階函數,與數據列表密切配合
  2. 函數式編程須要純函數,即不會產生反作用或修改輸入數據的函數

JavaScript 數組slice方法符合這兩個標準。數組

slice方法能夠在不修改原始列表的狀況下建立列表子集的淺拷貝。所以,它爲編寫函數式 JS 提供了一個關鍵的構建塊。瀏覽器

在這篇文章中,咱們將經過實例來掌握slice方法,探索它的8種不一樣用法。babel

注意: slice 方法不要與 splice方法混淆, splice方法會修改原始數組。

slice 工做原理

在深刻研究一些更高級的用法以前,讓咱們看一下slice方法的基礎知識。app

MDN文檔,slice 是數組上的一個方法,它最多有兩個參數:dom

arr.slice([begin[, end]])

begin函數式編程

從該索引處開始提取原數組中的元素,若是該參數爲負數,則表示從原數組中的倒數第幾個元素開始提取,slice(-2)表示提取原數組中的倒數第二個元素到最後一個元素(包含最後一個元素)。
若是省略 begin,則 slice 從索引 0 開始。

end

在該索引處結束提取原數組元素(從0開始)。slice會提取原數組中索引從 beginend 的全部元素(包含begin,但不包含end)。

slice(1,4) 提取原數組中的第二個元素開始直到第四個元素的全部元素 (索引爲 1, 2, 3的元素)。

若是該參數爲負數, 則它表示在原數組中的倒數第幾個元素結束抽取。 slice(-2,-1)表示抽取了原數組中的倒數第二個元素到最後一個元素(不包含最後一個元素,也就是隻有倒數第二個元素)。

若是 end 被省略,則slice 會一直提取到原數組末尾。若是 end 大於數組長度,slice 也會一直提取到原數組末尾。

基本用法

咱們的前4個例子突出slice的核心功能。

用法1:簡單的複製

const arr2 = arr.slice

沒有任何參數的slice執行一個簡單的淺拷貝。當前,主流的用法仍是使用展開運算符合來實現,可是若是在舊的代碼庫中,或者沒有使用babel的構建步驟,可能仍然但願使用slice

用法2:獲取從 N 開始的子數組

使用slice方法最簡單的方法就是原始數組從N開始抽取的全部元素。

一種狀況是但願彈出數組的第一個元素並使用它,返回剩餘的數組,但但願在不修改原始數組的狀況下執行此操做。

function useone (arr) {
  const usedItem = arr[0]
  return arr.slice(1)
}

用法3:獲取從末尾 N 開始的子數組

slice的另外一種使用方法是獲取數組的末尾,利用的是負索引從末尾開始計數。

這種負索引使刪除任意數量的元素變得超級簡單。例如,若是你只想抓取3個

const last3 = arr.slice(-3)

用法4:獲取數組的前n個

獲取數組的前面的數,咱們須要使用第二個參數:end

當有兩個參數時,slice方法返回一個從begin開始但不包括end的集合。

因爲JavaScript數組是從0開始的(索引從0開始),這使得獲取前N個元素變得很是簡單:

const first4 = arr.slice(0, 4)

用法5:獲取數組中某段子數組

若是咱們想要使用slice從任何索引開始獲取數組的一段,該怎麼辦?

爲此,咱們須要從 (begin, length) 轉換爲(begin, end)。 計算邏輯很簡單,咱們能夠定義一個簡單的函數來作到這一點:

function pullSegment(arr, begin, length) {
  return arr.slice(begin, begin + length);
}

處理相似數組的對象

JavaScript中,數組是一個特殊的對象,其property名爲正整數,且其length屬性會隨着數組成員的增減而發生變化,同時又從Array構造函數中繼承了一些用於進行數組操做的方法。

而對於一個普通的對象來講,若是它的全部property名均爲正整數,同時也有相應的length屬性,那麼雖然該對象並非由Array構造函數所建立的,它依然呈現出數組的行爲,在這種狀況下,這些對象被稱爲 「類數組對象」 。

slice方法也可用於相似數組的對象。

一些相似數組包如arguments(用於訪問傳遞給函數的全部參數的關鍵字),NodeLists(從返回節點列表的任何DOM API方法返回),甚至是使用數字索引並添加length屬性的原始對象。

要在相似數組的對象上使用slice方法,須要直接從Array.prototype引用它,以下所示:

Array.prototype.slice.call(arguments)

在這特定的場合中會頗有用處。

用法6:將相似數組的對象轉換爲數組

slice在相似數組的對象上的一個常見用途是將它們轉換爲實際數組。 例如:

const args = Array.prototype.slice.call(arguments);

你爲何要這麼作?爲了使用數組方法。例如,想象一個像這樣的函數

function addOne() { 
  return arguments.map(i => i+1); 
}

這看起來可行,但若是你試着去作,你就會獲得錯誤:

> addOne(1, 2, 3)
TypeError: arguments.map is not a function
    at test (repl:2:18)
    at repl:1:1
    at ContextifyScript.Script.runInThisContext (vm.js:44:33)
    at REPLServer.defaultEval (repl.js:239:29)
    at bound (domain.js:301:14)
    at REPLServer.runBound [as eval] (domain.js:314:12)
    at REPLServer.onLine (repl.js:440:10)
    at emitOne (events.js:120:20)
    at REPLServer.emit (events.js:210:7)
    at REPLServer.Interface._onLine (readline.js:279:10)

這是由於arguments 實際上不是數組,而是相似數組的對象。 可使用slice實現此功能,以下所示:

function addOne() {
  return Array.prototype.slice.call(arguments).map(i => i+1)
}

如今就能夠獲得了你所但願的數據:

> addOne(1, 2, 3) 
 [ 2, 3, 4 ]

用法7:將任意長度多餘的參數強制轉換爲數組

有時但願接受函數的多餘參數,組成一個數組。

較新版本的JavaScript引入了所謂的Rest語法來處理這個問題,可是若是爲爲了兼容舊瀏覽器,你可使用slice作到這一點:

function myFunc(a, b) { 
  const extraArgs = Array.prototype.slice.call(arguments, 2); 
}

這容許使用任意數量的參數調用myFunc, 例如:

myFunc(1, 2, 3, 4, 5, 6, 7, 8)

在函數裏面會獲得a == 1b === 2extraArgs=== [3,4,5,6,7,8]

用法8:修改數組中的特定索引

slice在函數上下文中一個強大而常見的用法是替換數組中特定項的值。

從本質上講,這很簡單,只須要分配新值,可是在函數世界中,不能修改原始數組。

相反,能夠將slice與擴展運算符一塊兒使用,以返回一個相同但對於要更新的​​索引的新數組:

function replaceIdx(arr, index, newVal) {
  return [
    ...arr.slice(0, index),
    newVal,
    ...arr.slice(index + 1)
  ]
}

偏函數應用

偏函數應用,英文是partial application,也能夠譯做「局部應用」、「部分應用」、「偏應用」

函數式編程中的另外一種常見模式是所謂的偏函數應用:將函數預先應用於函數,而後返回一個新函數。

這種模式容許你組合函數,經過使用具備不一樣預應用參數的相同核心函數來建立更大的可重用性。

雖然像Haskell這樣的純函數語言自己支持偏函數應用程序,可是在JavaScript中,咱們可使用slice實現一個函數來實現它

var partial = function() {
  const fn = arguments[0];
  const args = Array.prototype.slice.call(arguments, 1);

  // Return a function that calls fn
  return function() {
    var remainingArgs = Array.prototype.slice.call(arguments);
    return fn.apply(this, args.concat(remainingArgs));
  }
}

交流

我是小智,公衆號「大遷世界」做者,對前端技術保持學習愛好者。我會常常分享本身所學所看的乾貨,在進階的路上,共勉!

關注公衆號,後臺回覆福利,便可看到福利,你懂的。

clipboard.png

相關文章
相關標籤/搜索