返回

this的指向 & call apply bind的内部实现剖析

前端

相信很多朋友对this的指向经常遇到,本文总结了this的几种主要场景的指向。并且对call apply bind这三种改变this指向的底层方法进行了实现。

this的指向

对于this,我们首先会碰到一个疑问:this指向什么

我们先看一看场景:

  1. 看方法前面是否有点,如果没有 ,那么它的指向在严格模式下是undefined,非严格模式下指向的是window;如果方法前面有点,那么点前面是谁,this就指向谁。

  2. 普通函数的情况

let obj = {
    name: "obj",
    getName: function() {
        return this.name;
    }
};

let getName = obj.getName;
console.log(obj.getName()); // obj
console.log(getName()); // undefined

在上面的代码中,this的指向取决于函数的调用方式。obj.getName()中,this指向obj。而在getName()中,this指向undefined,因为普通函数作为参数被调用时,this指向全局对象window(非严格模式下)。

  1. 箭头函数的情况

箭头函数的this指向是由其所在的环境决定的。在上面的代码中,箭头函数getNameArrow()被定义在obj对象中,因此它的this指向obj对象:

let obj = {
    name: "obj",
    getNameArrow: () => {
        return this.name;
    }
};

console.log(obj.getNameArrow()); // obj
  1. 构造函数的情况

构造函数的this指向new创建的实例对象。在下面的代码中,this指向Person实例对象:

function Person(name) {
    this.name = name;
}

let person = new Person("John");
console.log(person.name); // John

call apply bind的内部实现剖析

现在我们了解了this的指向,我们再来看看call apply bind这三个函数是如何改变this指向的。

这三个函数的实现原理是相似的,都是通过改变函数的执行上下文来改变this的指向。

其中,call函数的实现如下:

Function.prototype.call = function(context, ...args) {
    // 将this指向context对象
    context.fn = this;
    // 将参数args传给函数fn
    const result = context.fn(...args);
    // 删除context.fn属性
    delete context.fn;
    // 返回函数fn的执行结果
    return result;
};

apply函数的实现如下:

Function.prototype.apply = function(context, args) {
    // 将this指向context对象
    context.fn = this;
    // 将参数args传给函数fn
    const result = context.fn(...args);
    // 删除context.fn属性
    delete context.fn;
    // 返回函数fn的执行结果
    return result;
};

bind函数的实现如下:

Function.prototype.bind = function(context, ...args) {
    // 创建一个新的函数fn
    const fn = (...bindArgs) => {
        // 将this指向context对象
        this.fn = this;
        // 将参数bindArgs和args传给函数fn
        const result = this.fn(...args, ...bindArgs);
        // 删除this.fn属性
        delete this.fn;
        // 返回函数fn的执行结果
        return result;
    };
    // 返回新的函数fn
    return fn;
};

从上面的代码中,我们可以看到,call apply bind这三个函数的实现原理都是相似的,都是通过改变函数的执行上下文来改变this的指向。

但是,这三个函数在使用上有一些区别:

  • call函数的参数是context和args,其中context是this要指向的对象,args是传递给函数的参数。
  • apply函数的参数是context和args,其中context是this要指向的对象,args是一个数组,里面包含了传递给函数的参数。
  • bind函数的参数是context和args,其中context是this要指向的对象,args是传递给函数的参数。bind函数不会立即执行函数,而是返回一个新的函数,这个新的函数的this指向是context,并且它的参数是bind函数的参数args和新的参数。

希望这篇博客对您有所帮助。如果您有任何问题,请随时给我留言。