实现call、apply、bind

涉及相关面试题:call、apply以及bind函数内部是如何实现的?

Function.prototype.myCall()

首先从如下几点考虑如何实现这几个函数

  • 不传入第一个参数,那么上下文默认为window
  • 改变了this指向,让新的对象执行该函数,并能接受参数

代码示例:

Function.prototype.myCall = function(context=window){
    if(typeof this !== 'function') throw new Error('error:not a function')
    
    const args = [...arguments].slice(1)
    context.fn = this
    const result = context.fn(...args)
    delete context.fn
    retrun result
}
1
2
3
4
5
6
7
8
9

实现分析:

  • 首先context为可选参数,如果不传则默认为window
  • 接下来给context创建一个fn属性,并将值设置为需要调用的函数
  • 因为call可以传入的多个参数作为调用函数的参数,所以需要将参数抽离出来
  • 然后调用函数并将对象上的函数删除

Function.prototype.myApply()

applycall类似,因为applycall传递参数的方式不同,则只需要修改参数传递即可

代码示例:

Function.prototype.myApply = function(context=window) {
    if(typeof this !== 'function') throw new Error('error:not a function')
    
    context.fn = this
    let result;
    if(arguments[1]) {
       result = context.fn(...arguments[1])
       } else {
       result = context.fn()
    }
    return result
}
1
2
3
4
5
6
7
8
9
10
11
12

Function.prototype.myBind()

bind需要返回一个函数,需要判断一些边界条件

代码示例:

Function.prototype.myBind = function(context=window) {
    if(typeof this !== 'function') throw new Error('error:not a function')
    
    const self = this
    const args = [...arguments].slice(1)
    return function F(){
        if(self instanceof F) return new self(...args,...arguments)
        return self.apply(context,args.concat(...arguments))
    }
}
1
2
3
4
5
6
7
8
9
10

实现分析:

  • 前几步与上述实现相同,不多赘述
  • bind返回了一个函数,对于函数来说有两种调用方式,一种是直接调用,一种是构造函数式调用,首先来说直接调用方式
  • 对于直接调用来说,这里选择apply的方式实现,但是对于参数需要注意以下情况:因为bind可以实现类似于这样的代码f.bind(obj,1)(2),所以我们需要将两边的参数拼接起来,于是就有了这样的实现args.concat(...arguments)
  • 最后来讲通过new的方式来实现,对于new的情况来说,不会被任何方式改变this,所以对于这种情况我们需要忽略传入的this
上次更新: 9/25/2019, 9:54:29 AM