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会自动执行对应的函数。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章