【模拟实现】Call/Apply/Bind

3/24/2021 面试模拟实现

# 原理

三个方法经常用来改变this的指向。 其中 callapply是立即执行的,bind返回一个函数下次调用。

# 使用场景

callapply的使用场景

  1. 对象继承
  2. 借用方法

# 代码实现

/**
 * 模拟实现 call
 * this 指向要调用的函数
 * @param {*} context 传入的对象
 * @param  {...any} args 参数
 */
Function.prototype.myCall = function(context, ...args) {
  const obj = context ? new Object(context) : window
  const key = Symbol()
  obj[key] = this
  const result = obj[key](...args)
  delete obj[key]
  return result
}

/**
 * 模拟实现 apply
 * this 指向要调用的函数
 * @param {Object} context 传入的对象
 */
Function.prototype.myApply = function(context) {
  const obj = context ? new Object(context) : window
  const args = arguments[1]
  const key = Symbol()
  obj[key] = this
  const result = args ? obj[key](...args) : obj[key]()
  delete obj[key]
  return result
}

/**
 * 模拟实现 bind
 * this 指向要调用的函数
 * @param {Object} context 传入的对象
 * @param  {...any} args 
 */
Function.prototype.myBind = function(context, ...args) {
  const fn = this
  const bindFn = function (...newFnArgs) {
    return fn.call(
      this instanceof bindFn ? this : context,
      ...args,
      ...newFnArgs
    )
  }
  bindFn.prototype = Object.create(fn.prototype)
  return bindFn
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

# 测试一下

window.name = 'Rocky'
const person1 = {
  name: 'Tom',
  say(arg1, arg2) {
    console.log(`my name is ${this.name}, ${arg1}-${arg2}`)
  }
}
const person2 = {
  name: 'Jerry'
}

person1.say('aaa', 'bbb') // Tom
person1.say.call(person2, 'ccc', 'ddd') // Jerry
person1.say.myCall(null, 'ddd', 'eee')  // Rocky
person1.say.myApply(person2, ['fff', 'ggg']) // Jerry
person1.say.myApply(null, ['hhh', 'iii']) // Rocky
var newSay = person1.say.bind(person2, 'jjj')
newSay('kkk', 'lll')  // Jerry jjj-kkk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Last Updated: 4/3/2021, 10:11:35 AM