Lodash源碼講解-slice函數

本文首發於技術風暴-Lodash源碼講解javascript

這是咱們閱讀源碼的第1篇博客,這一篇博客主要介紹Lodashslice函數,這個函數內部的實現沒有依賴別的函數;咱們這篇博客就來說解一下這個slice函數。html

咱們首先來看一下這個函數的源碼,源碼以下所示:java

/**
 * Creates a slice of `array` from `start` up to, but not including, `end`.
 *
 * **Note:** This method is used instead of
 * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are
 * returned.
 *
 * @since 3.0.0
 * @category Array
 * @param {Array} array The array to slice.
 * @param {number} [start=0] The start position.
 * @param {number} [end=array.length] The end position.
 * @returns {Array} Returns the slice of `array`.
 */
function slice(array, start, end) {
  // #1  
  let length = array == null ? 0 : array.length
  if (!length) {
    return []
  }
  // #2
  start = start == null ? 0 : start
  end = end === undefined ? length : end
    
  // #3  
  if (start < 0) {
    start = -start > length ? 0 : (length + start)
  }
  end = end > length ? length : end
  if (end < 0) {
    end += length
  }
  // #4
  length = start > end ? 0 : ((end - start) >>> 0)
  start >>>= 0

  // #5 
  let index = -1
  const result = new Array(length)
  while (++index < length) {
    result[index] = array[index + start]
  }
  return result
}

export default slice

首先咱們來講一下這個函數的做用,它的做用就是獲取一個數組的切片;所謂切片,就是指數組的一部分連續元素,固然也能夠是數組的所有元素。咱們這時可能想到了數組自己就有一個slice方法,那咱們爲何不使用原生的數組的那個slice方法而非要本身從新寫一個呢?git

有兩個緣由:github

  • 更好的兼容性,確保了IE瀏覽器在版本小於9的狀況下,對於元素節點列表的操做能夠返回一個密集的數組(dense-arrays,這個不太好翻譯)
  • 比原生的方法效率更高,這個會在本文的後面有一個對比圖。

下面咱們就來好好看一下這個函數,首先這個函數須要接收三個參數,可是後兩個參數不是必須選擇的;第一個參數是一個數組,能夠是元素的節點集合;第二個參數表示開始截取切片的位置,第三個參數表示的是切片截取的截至位置,可是不包含這個數所在位置的元素。數組

接下來是分步驟的講解,我在相應的位置作了標記,你們看的時候能夠找標記的位置,下面的講解就是按照標記的位置來的。瀏覽器

  • #1:咱們使用了三目運算符來判斷是否傳入了一個數組,若是沒有傳入數組咱們直接把數組的長度設置爲0;反之,咱們就獲取數組的長度;而後作了一個判斷,若是數組的長度爲0,咱們直接返回一個空的數組。
  • #2:判斷參數startend是否存在;若是都存在的話,就取傳入的這個值;若是不存在的話,start的取值默認爲0, end的取值默認爲數組的長度。
  • #3:判斷參數start是不是負數;若是start是負數的話,再比較一下start的相反數與數組長度的大小,若是大於數組的長度,那麼就賦值爲0;反之,就把start賦值爲length + start,也就是從數組的後面開始數開始截取的位置;而後判斷一下end是否大於數組的長度,若是大於數組的長度,那麼就把它賦值爲數組的長度;而後判斷一下end是否小於0,若是小於0的話,就賦值爲end + length,也就是從後向前數結束的位置。
  • #4:咱們看到>>>這樣一個操做符,這個是按位移動操做符,表示向右無符號移動;咱們先來看一下代碼,首先判斷start是否大於end,若是大於end就把length的值設爲0,不然就把end減去start而後向右無符號移動零位;而後把start向右無符號移動零位。那麼這裏爲何要使用>>>這個按位操做符呢?首先咱們要了解>>>的做用,>>>的做用就是把一個數字,變成一個無符號的32位的整數,那麼num >>> 0的做用,就是把num變成一個無符號的32位的整數,不論num是負數仍是小數。並且咱們還須要知道,JavaScript的數組的最大長度是2^32-1,因此這樣作也避免了數組的索引超出界限。
  • #5:上一步計算出了咱們要取的數組的長度,而後咱們在這一步就新建立了一個數組,而後將咱們要獲取的數組的值,從原數組中拷貝過來;而後返回這個數組。

到這裏,咱們已經把這個函數須要注意的地方都講解了一下;那麼接下來就須要咱們本身去實現這麼一個函數了,slice是我實現的一個版本。你們能夠去好好練一下啦,沒有什麼特別困難的地方。app

對了,上面咱們說了要比較一下_.slice和原生的[].slice方法的性能,下圖是在個人電腦上的一個測試,你們也能夠本身測試測試一下,測試的連接是slice-vs-slicejsp

圖片描述

從上圖能夠明顯的看到,_.slice方法比原生的[].slice方法性能要好不少。函數

相關文章
相關標籤/搜索