apply,call,bind

171 阅读2分钟

apply , call , bind

我们先来明确一下this。this 是指当前代码的运行环境。 如果一段代码是直接运行在浏览器的,比如说在浏览器的控制台。this就是当前的浏览器window,如果是在node 中,this就指向global。如果是在一个对象 a,那么对象中的一个方法打印this 的时候,this就是这个对象a。其实window 就是一个对象。那我们就可以记住,this 就是指向对象。

1. call , apply, bind 都是为了改变某个函数运行时的上下文(context)而存在的

换句话说,就是为了改变函数体内部 this 的指向。要知道只有方法才能调用call,apply,bind。 bala.. ,bala 一大堆。

但是也可以这样想,这三个就是正常的js 方法。的确,本来也就是正常的js 方法,只不过我们用的少。不熟悉。 那接着来看下面很常用的一个方式

Math.max(9,1,2,3)

Math.max.call(null,9,1,2,3);

Math.max.apply(null,[9,1,2,3]);

Math.max.bind(null,9,1)(2,3)

抛开刚才所有的解释,忘记刚才所有的话,call 和applay 的用法就是。

fn.call(obj,1,2,3,4);
fn.apply(obj,[1,2,3,4]);

// 其实就像这样
obj.fn(1,2,3,4)

解释就是

call和applyobj 这个对象能调用fn 这么一个方法。告诉浏览器,这个对象下 有fn 的这个方法,obj 可以调用fn 这就是call 和apply 的作用,不要去想改变了this 的指向。改变this指向是它们的实现方法。call 方法的第二个位置参数就是很多数字,apply 第二个位置参数就是一个数组。

bind 的用法和call 一样,第一个参数都是传一个obj,第二个位置参数是很多数字。只不过它的返回值是一个方法。

位置参数就是给fn 的参数,只不过apply 接受参数,是接受一个数组 需要注意的是:apply 的第二个数组参数,整个数组里面的元素是fn 的参数。,call 和bind 是接受散装参数。

2.怎么手写一个类似的call ,或者apply 呢?

call ,apply,bind 都是只有方法才能调用所以我们在 方法的原型上直接定义

    Function.prototype._call=function($this,...args){
    // 在call 方法中,这个时候的this,就是指向 调用call 的那个方法
    $this.fn = this;
    reurn $this.fn(...args);

}

这个是最简单的call 方法我们需要完善它

Function.prototype._call=function($this,...args){
	
    // 这一步,如果$this = null ,则可以这样直接挂载到window 上
    $this=$this||window||global;
    // 定义一个唯一变量 symbol,这样可以防止我们要调用的方法和自定义的方法重命名
    const fn = Symbol('fn');
    // 将要调用的方法挂载到我们的实例上
    $this[fn] = this;
    
    // 获取结果
    const result = $this[fn](...args);
    // 删除,防止重命名和污染变量
    delete $this[fn];
    
    return result;
}

同样的手写 apply

Function.prototype._apply=function($this,args){
	
     $this=$this||window||global;
    let fn = Symbol('fn');
    $this[fn] = this;
    const result = $this[fn](...args);
    delete $this[fn];
    return result;

}

同样的手写 bind

知道bind 与call 的区别就是bind 返回了一个方法,所以。。。

Function.prototype._bind = function ($this, ...args) {
    var fn = this;
    $this = $this || global || window;
    var res = function () {
        return fn.apply(this instanceof fn ? this : $this, args.concat(Array.prototype.slice.call(arguments)));
    }
    if (fn.prototype) {
        res.prototype = Object.create(fn.prototype);
    }
    return res;
}