call,apply,bind的內部原理實現


call

call 方法使用一個函數執行的時候更改本身 this 指向,並傳入一個或者多個參數。

var obj = {
  name: '$call'
}
function _fun() {
  console.log(this.name, ...arguments)
}

_fun.call(obj, 'call1', 'call2', 'call3') // $call call1 call2 call3

內部實現原理:

Function.prototype.$$call = function (context) {
  // 第一個參數為 this 指向值,如無則指向 window
  context = context || window
  // 將本身的函數保存下來,在后面需要執行,這一步 this 的指向已經指向了 context 
  context.fn = this
  // 將后面傳入的參數轉為數組,取除第一個 this 指向剩下的所有參數
  let args = [...arguments].slice(1)
  // 執行函數本身,並將參數傳入
  let result = context.fn(...args)
  // 銷毀函數,避免作用域污染
  delete context.fn
  return result
}

apply

apply 方法同 call 一樣使用一個函數執行的時候更改本身 this 指向,只是傳參的時候只有一個,並且必須是數組(如果call與apply傳參類型記不清,可以根據方法的第一個字母來區分,apply -> a(首字母) -> array)。

var obj = {
  name: '$call'
}
function _fun() {
  console.log(this.name, ...arguments)
}

_fun.apply(obj, ['call1', 'call2', 'call3']) // $call call1 call2 call3

內部實現原理:

Function.prototype.$$apply = function (context) {
  // 第一個參數為 this 指向值,如無則指向 window
  context = context || window
  // 將本身的函數保存下來,在后面需要執行,這一步 this 的指向已經指向了 context 
  context.fn = this
  // 將后面傳入的參數轉為數組,取除第二個參數
  let args = [...arguments][1]
  // 如果第二個參數不是對象則報錯
  if (typeof args !== 'object') {
    throw Error('CreateListFromArrayLike called on non-object')
    return
  }
  // 執行函數本身,並將參數傳入
  let result = context.fn(...args)
  // 銷毀函數,避免作用域污染
  delete context.fn
  return result
}

bind

bind 方法與 call 和 apply 不同的點是后續的參數沒有要求,但是 bind 會返回一個 this 指向已改變的函數,相同的是第一個參數就是 this 指向值

var obj = {
  name: '$call'
}
function _fun() {
  console.log(this.name, ...arguments)
}

_fun.call(obj, ['call1'], 'call3')('call2') // $call ["call1"] call3 call2

內部實現原理:

Function.prototype.$$bind = function (context) {
  // 取bind執行的時候除第一個后續的所有參數
  let args = [...arguments].slice(1)
  // 函數本身緩存
  let _this = this
  // 返回函數
  return function () {
    // 合並返回函數執行傳入的參數
    let bindArg = [...args, ...arguments]
    // 再次調用時的函數本身執行
    return _this.call(context, ...bindArg)
  }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM