我们在学习JavaScript的时候,因为对一些概念不是很清楚,但是又会通过一些简洁的方式把它给记下来,那么这样自己记下来的概念和真正的概念产生了很强的偏差.
当然,还有一些以为这个是对的,还会把它发在网上,那么这个影响就大了,很多人都对于这个概念产生一个错误的理解.
比如对于this指向的理解中,有这样一种说法:谁调用它,this就指向谁。在我刚开始学习this的时候,我非常相信这句话。因为在一些情况下,这样理解也还算说得通。可是我常常会在开发中遇到一些不一样的情况,一个由于this的错误调用,可以让我懵逼一整天。那个时候我也查资料,在群里问大神,可是我仍然搞不清楚“我特么到底错哪里了”。
其实只是因为我的认知中有一个不准确的结论。
所以,我认为需要有这样一篇文章,来帮助大家全方位的解读this。让大家对this,有一个正确的,全面的认知。
在这之前,我们回顾一下执行上下文。
在前面几篇文章中,我有好几个地方都提到执行上下文的生命周期,为了防止大家没有记住,再发一次,如下图。
执行上下文生命周期
执行上下文的创建阶段,会分别生成变量对象,建立作用域链,确定this指向。其中变量对象与作用域链我们都已经明白了。本文的关键,就是确定this指向。
首先,我们需要得出一个非常重要的,并且一定要牢记于心的结论,**this的指向,是在函数被调用的时候确定的。**也就是执行上下文被创建时确定的。
因此,一个函数中的this指向,可以非常灵活。比如下面的例子中,同一个函数由于调用方式的不同,this指向了不一样的对象。
var a = 10;
var obj = {
a: 20
}
function fn() {
console.log(this.a);
}
fn(); // 10
fn.call(obj); // 20
除此之外,在函数执行过程中,this一旦被确定,就不可更改了。
var a = 10;
var obj = {
a: 20
}
function fn() {
this = obj; // 这句话试图修改this,运行后会报错
console.log(this.a);
}
fn();
一、全局对象中的this
关于全局对象的this,我之前在总结变量对象的时候提到过,它是一个比较特殊的存在。全局环境中的this,指向它本身。因此,这也相对简单,没有那么多复杂的情况需要考虑。
// 通过this绑定到全局对象
this.a2 = 20;
// 通过声明绑定到变量对象,但在全局环境中,变量对象就是它自身
var a1 = 10;
// 仅仅只有赋值操作,标识符会隐式绑定到全局对象
a3 = 30;
// 输出结果会全部符合预期
console.log(a1);
console.log(a2);
console.log(a3);
二、函数中的this
在总结函数中this指向之前,我想我们有必要通过一些奇怪的例子,来感受一下函数中this的捉摸不定。
// demo01
var a = 20;
function fn() {
console.log(this.a);
}
fn();
// demo02
var a = 20;
function fn() {
function foo() {
console.log(this.a);
}
foo();
}
fn();
// demo03
var a = 20;
var obj = {
a: 10,
c: this.a