持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第25天,点击查看活动详情
前言
🥲 昨天在某技术社群里面看到这样一个问题和这样的回答
- 在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();
可以根据上面的代码和输出值去思考一下,为什么this.a 指向了 外部的变量 a
var a = 1就是一个全局作用域下的变量- 当调用
foo函数时,应用了this中默认绑定的规则,因此this就指向了全局对象
虽然说是应用了 默认绑定的规则,但是我们怎么知道这里应用到了呢?
- 我们可以通过分析调用位置来确定
foo函数是一个不带任何修饰的函数引用进行调用的,因此只能使用默认绑定,无法应用其他的绑定规则。
隐藏式绑定,查看调用位置是否有上下文对象
function foo(){
console.log('输出:', this.a);
}
var obj = {
a: 1,
foo: foo
};
obj.foo();
此时并没有在外部添加全局变量 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();
- 这里的输出结果就和上面的不一样了。
- 因为这个的
bar虽然是obj.foo的一个别名,但是实际上,它引用的是foo函数本身,因此bar()就变成了一个不带任何修饰的函数调用,也就变成了之前的规则 -默认绑定
总结
在项目开发过程中,还是需要理解一些原理性的东西,不能盲目的做开发,需要了解底层。
本篇文章主要是和大家一起了解 this 的绑定关系,顺带说明了调用位置的内容。
欢迎大家补充更多知识点。一起学习,一起成长!!!