call、apply、bind 原理實現

目錄

1. call 的模擬實現

2. apply 的模擬實現

3. bind 的模擬實現

4. 三者異同


學習並參考於

JavaScript深入之call和apply的模擬實現

JS的call,apply與bind詳解,及其模擬實現


(一)call的模擬實現

call 用法MDN Function.prototype.call()

call() 方法使用一個指定的 this 值和可選的參數列表來調用一個函數。

call() 提供新的 this 值給當前調用的函數/方法。

1. call 實現主要思路

  • 將函數設爲對象的屬性

  • 執行該函數

  • 刪除該函數

另外還有考慮:

  • call 函數還能給定參數執行函數
  • this 參數不傳,或者傳null,undefined, this指向window對象
  • 函數是可以有返回值的

2. 實現

Function.prototype.myCall = function () {
  if (typeof this !== 'function') {
    throw new TypeError('error!')
  }
  let context = arguments[0] || window   //this 參數可以傳 null,當爲 null 的時候,視爲指向 window
  context.fn = this  // 首先要獲取調用call的函數,用this可以獲取
  let args = [...arguments].slice(1) //從 Arguments 對象中取值,取出第二個到最後一個參數   
  let result = context.fn(...args)  //函數是可以有返回值的
  delete context.fn
  return result
}

3. 測試

// 測試一下上面實現的myCall
var value = 2;

var obj = {
    value: 1
}

function bar(name, age) {
    console.log(this.value);
    return {
        value: this.value,
        name: name,
        age: age
    }
}

bar.call(null); // 2

console.log(bar.myCall(obj, 'kevin', 18));
// 1
// Object {
//    value: 1,
//    name: 'kevin',
//    age: 18
// }

(二)apply 的模擬實現

apply 用法MDN Function.prototype.apply()

apply() 方法使用一個指定的 this 值和可選的參數數組 來調用一個函數。

apply 的實現跟 call 類似。

1. 實現

Function.prototype.myApply = function () {
  if (typeof this !== 'function') {
    throw new TypeError('error!')
  }
  let context = arguments[0] || window
  context.fn = this
  let result = arguments[1] ? context.fn(...arguments[1]) : context.fn()
  delete context.fn
  return result
}

2. 測試

var foo = {
    value: 1
}
function bar(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value);
}
bar.myApply(foo, ['black', '18']) // black 18 1

(三)bind 的模擬實現

bind 用法MDN Function.prototype.bind()

bind()方法會創建一個新函數,稱爲綁定函數。當這個新函數被調用時,bind() 的第一個參數將作爲它運行時的 this,之後的一序列參數將會在傳遞的實參前傳入作爲它的參數。

bind是ES5新增的一個方法,不會執行對應的函數,而是返回對綁定函數的引用。

1. 實現

Function.prototype.customBind = function () {
  if (typeof this !== 'function') {
    throw new TypeError('error!')
  }
  const that = this   // 首先要獲取調用bind的函數,用this獲取並存放在that中
  let context = arguments[0] || window
  const args = [...arguments].slice(1)
  return function() {
    return that.apply(context, args.concat([...arguments]))
  }
}

(四)三者異同

1. 相同

  • 改變函數體內 this 的指向

2. 不同

  • call、apply的區別:call方法接受的是參數列表,而apply方法接受的是一個參數數組
  • bind不立即執行。而call或apply會自動執行對應的函數。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章