【this绑定和调用】全面解析JavaScript中this的绑定关系和调用位置

193 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第25天,点击查看活动详情

前言

🥲 昨天在某技术社群里面看到这样一个问题和这样的回答

fe54c9ed6de4a28ab2e18ea18f86bf9.png

9cdcc96ffe55207f2695c6ef36cbbe4.jpg
  • 在js方法中自己调用自己需要加 this 嘛?

🤪 这就是今天这篇文章要讨论的问题了。

this调用

本来是想直接写绑定规则的,但是在理解 this 的绑定过程之前,需要先去理解 this调用位置

调用位置就是函数在代码中被调用的位置(非声明位置)

在函数之中去找到被调用的位置,就是去分析它的调用栈,比如下面这段代码,就可以很好的理解每个函数之间的调用栈

function a(){
    // 当前方法的调用栈:a
    // 所以 a 函数的调用位置就是全局作用域

    console.log('a');
    b();    // 这里去调用 b 函数,也就是 b 函数的调用位置
}

function b(){
    // 当前方法的调用栈:a -> b
    // 所以 b 函数的调用位置就是在 a 函数中
    
    console.log('b');
    c();    // 这里去调用 c 函数,也就是 c 函数的调用位置
}

function c(){
     // c 函数同理,调用栈:a -> b -> c
     // 所以 c 函数的调用位置就是在 b 函数中
     
    console.log('c');
}

a();     // 这里就是 a 函数的调用位置了

由于在代码外部不能清晰的解释,所以把分析过程都写在的注释代码中。

🤔 其实理解上面的代码和调用栈、调用位置并不难,你可以把调用栈理解为一个函数调用链,虽然看起来简单,但是在实际运用过程中是非常容易出错的。

🤔 所以你可以使用浏览器中的调试工具去查看调用栈的方法;亦或者是用debugger也可以。

this绑定

🤫 为什么说理解this 的绑定过程之前,需要先去理解 this调用位置

  • 因为在函数的执行过程中,调用位置决定了 this 的绑定对象。

默认绑定,也可以理解为独立函数调用

function foo(){
    console.log('输出:', this.a);
}

var a = 1;
foo();

image.png

可以根据上面的代码和输出值去思考一下,为什么this.a 指向了 外部的变量 a

  • var a = 1 就是一个全局作用域下的变量
  • 当调用 foo 函数时,应用了 this中默认绑定的规则,因此 this 就指向了全局对象

虽然说是应用了 默认绑定的规则,但是我们怎么知道这里应用到了呢?

  • 我们可以通过分析调用位置来确定 foo 函数是一个不带任何修饰的函数引用进行调用的,因此只能使用默认绑定,无法应用其他的绑定规则。

隐藏式绑定,查看调用位置是否有上下文对象

function foo(){
    console.log('输出:', this.a);
}

var obj = {
    a: 1,
    foo: foo
};

obj.foo();

image.png

此时并没有在外部添加全局变量 a ,为什么 this.a 还会有输出结果呢?

  • 我们可以看看 foo 函数的声明方式,它被指向了 obj 对象
  • 当函数被引用时,就拥有了传说中的上下文对象,这时候就会出现 隐藏式绑定 规则把函数调用当中的 this 绑定到这个所谓的上下文对象里面
  • 因为调用 foo 函数时 this 被绑定到 obj 对象中,所以 this.a obj.a 没啥区别了

🤨 如果这个时候,你在外部添加一个全局变量 a ,并且给函数加一个别名,会出现什么情况呢?

function foo(){
    console.log('输出:', this.a);
}

var obj = {
    a: 1,
    foo: foo
};

var bar = obj.foo;     // 取个别名

var a = 2;     // 这里添加一个全局变量

bar();

image.png

  • 这里的输出结果就和上面的不一样了。
  • 因为这个的 bar 虽然是 obj.foo 的一个别名,但是实际上,它引用的是 foo 函数本身,因此 bar() 就变成了一个不带任何修饰的函数调用,也就变成了之前的规则 - 默认绑定

总结

在项目开发过程中,还是需要理解一些原理性的东西,不能盲目的做开发,需要了解底层。

本篇文章主要是和大家一起了解 this 的绑定关系,顺带说明了调用位置的内容。

欢迎大家补充更多知识点。一起学习,一起成长!!!