LeoWangJ / blog

紀錄學習文章
1 stars 0 forks source link

手寫bind #16

Open LeoWangJ opened 5 years ago

LeoWangJ commented 5 years ago

在開發時多少有使用過bind這個方法,但是卻沒有想過他是怎麼實現的,今天就要來研究一下。
先來看mdn 的定義:

bind() 方法,會建立一個新函式。該函式被呼叫時,會將 this 關鍵字設為給定的參數,並在呼叫時,帶有提供之前,給定順序的參數。

polyfill


var slice = Array.prototype.slice
function bind(){
 var that = arguments[0]
 var thatArgs = slice.call(arguments, 1)
 var fn = this

  if(typof fn !== function){
    throw new Error('bind 必須調用在函數上')
  }

  return function(){
      var funcArgs = slice.call(arguments,0)
      return fn.apply(that, thatArgs.concat(funcArgs))
  }
}

我們來一次拆分函數:

  1. 我們先將Array.slice的方法存到變數slice中,方便之後要處理arguments的值。
  2. 接著將arguments的第一個參數,也就是傳入要修改的this值存到that變數中。
  3. 將剩餘的參數存至thatArgs中,再將當前this存到fn變數中。
  4. 這個fn就是我們bind的函數,所以若bind的不是函數則會拋出錯誤。
  5. 因為bind會返回一個函數,所以我們這邊也會回傳函數。
  6. 函數中使用funcArgs用來儲存返回的函數中所傳的參數。
  7. 接著使用apply將傳入的this以及將全部參數加入綁定到fn函數中。

    但是這個bind還有一個問題是當我們使用new時會出現錯誤。


var slice = Array.prototype.slice
function bind(){
 var that = arguments[0]
 var thatArgs = slice.call(arguments, 1)
 var fn = this

  if(typof fn !== function){
    throw new Error('bind 必須調用在函數上')
  }

  function resultsFn(){
      var funcArgs = slice.call(arguments,0)
      return fn.apply(
       resultsFn.prototype.isPrototypeOf(this) ? this : that, 
       thatArgs.concat(funcArgs)
       )
  }
  resultsFn.prototype = fn.prototype
  return resultsFn
}

上面程式碼就使我們支援new 方法呼叫bind