# 实现 call

Function.prototype.myCall = function(context, ...args) {
  //判断边界条件
  if (typeof this !== 'function')
    throw new Error('caller must be a function!调用对象不是函数')
  context = context || globalThis
  //传入context为基本类型时,将其转为对应的引用类型
  if (typeof context !== 'object') context = new context.constructor(context)
  // 将函数(this)挂在待绑定的this上下文下面,然后调用
  const key = Symbol('key') //设置唯一值
  context[key] = this
  //调用函数
  const result = context[key](...args)
  delete context[key]
  return result
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

另一种写法:

Function.prototype.call = function(context) {
  if (typeof this !== 'function') {
    throw new Error(
      'Function.prototype.bind - what is trying to be bound is not callable'
    )
  }
  /* Array.prototype.slice.call(arguments) */
  /* let L = arguments.length,
    args = []
  for (let i = 1; i < L; i++) {
    args.push(arguments[i])
  } */
  args = [...arguments]
  let key = Symbol('key')
  context[key] = this
  eval('context[key](' + args + ')')
  delete context[key]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 实现 apply

apply 和 call 类似,只是参数类型不同,apply 的参数是数组,call 的参数是一个个的值

Function.prototype.myApply = function(context, args = []) {
  //判断边界条件
  if (typeof this !== 'function')
    throw new Error('caller must be a function!调用对象不是函数')
  context = context || globalThis
  //传入context为基本类型时,将其转为对应的引用类型
  if (typeof context !== 'object') context = new context.constructor(context)
  if (!Array.isArray(args)) {
    throw new TypeError('CreateListFromArrayLike called on non-object')
  }
  // 将函数(this)挂在待绑定的this上下文下面,然后调用
  context.fn = this
  //调用函数
  const result = context.fn(...args)
  delete context.fn
  return result
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

另一种写法:

Function.prototype.apply = function(context) {
  let args = arguments[1]
  let fn = Symbol('fn')
  context[fn] = this
  eval('context[fn](' + args + ')')
  delete context[fn]
}
1
2
3
4
5
6
7

# 实现 bind

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用

Function.prototype.myBind = function(context, ...args) {
  if (typeof this !== 'function') {
    throw new TypeError('caller must be a function!')
  }
  context = context || globalThis
  if (typeof context !== 'object') context = new context.constructor(context)
  //待绑定的函数
  let toBindFunc = this
  // 返回一个函数
  return function boundFunction() {
    // 因为返回了一个函数,可能会通过new调用
    if (this instanceof boundFunction) {
      //传入的参数覆盖默认参数
      return new toBindFunc(...args, ...arguments)
    }
    //传入的参数覆盖默认参数
    return toBindFunc.apply(context, args.concat(...arguments))
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19