实现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
2
3
4
5
6
7
8
9
实现分析:
- 首先
context为可选参数,如果不传则默认为window - 接下来给
context创建一个fn属性,并将值设置为需要调用的函数 - 因为
call可以传入的多个参数作为调用函数的参数,所以需要将参数抽离出来 - 然后调用函数并将对象上的函数删除
 
Function.prototype.myApply()
apply与call类似,因为apply与call传递参数的方式不同,则只需要修改参数传递即可
代码示例:
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
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
2
3
4
5
6
7
8
9
10
实现分析:
- 前几步与上述实现相同,不多赘述
 bind返回了一个函数,对于函数来说有两种调用方式,一种是直接调用,一种是构造函数式调用,首先来说直接调用方式- 对于直接调用来说,这里选择
apply的方式实现,但是对于参数需要注意以下情况:因为bind可以实现类似于这样的代码f.bind(obj,1)(2),所以我们需要将两边的参数拼接起来,于是就有了这样的实现args.concat(...arguments) - 最后来讲通过
new的方式来实现,对于new的情况来说,不会被任何方式改变this,所以对于这种情况我们需要忽略传入的this