为什么会有this

this在JavaScript中是一个非常复制的机制,它的存在其实是为了能让我们更好的复用代码,this提供了一种更优雅的方式来隐式“传递”一个对象引用,因此可以将API设计的更加简洁且易于复用。

我们举个例子:

new一个构造函数,我们可以得到一个新的实例对象,这个对象会继承原型,此时,如果没有this,如何在原型方法里去访问你的新的实例对象,以及获取属性这些操作。

显然是不太好做的,难道每次都把自身作为参数传递给prototype上的方法吗?

显然这非常不方便,如果使用了this,this会指向这个新的实例对象,那么我们在书写代码是就会更加方便了,复用也更加简单。

这个this不需要自己去声明,减少了大量啰嗦代码。

this的误区

如果不熟悉this到底是如何工作的,或者局限于字面的译意,很容易会产生误解,常见的两种错误认为:

  1. this指向自身
  2. this指向函数作用域

this指向自身

这个理解大部分人都是从字面译意上去理解的,我们看一个测试代码:

function foo(num) {
    console.log("foo: " + num);
    // 记录 foo 被调用的次数
    this.count++;
}

foo.count = 0;

var i;
for (i = 0; i < 10; i++) {
    if (i > 5) {
        foo(i);
    }
} 
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo 被调用了多少次?

console.log(foo.count); // 0 -- WT

如果this指向自身,那么函数foo上的count就应该为10,但是他是0。

this指向函数作用域

this会指向函数的作用域,如下代码:

function foo() {
    var a = 2;
    this.bar();
}

function bar() {
    console.log(this.a);
}

foo(); // undefined

仔细阅读,你会发现,this.bar函数被正确获取到并运行了,但是在打印this.a的时候报错了,因为RHS查询没有在作用域中查询到该变量。

这样看上去this好像确实是指向了函数作用域,并通过作用域链查找到了bar函数。通过作用域的知识我们知道,bar函数的作用域里面没有a变量,因为它的作用域只有它自己,以及上层的全局作用域,所以它抛错也是可以理解的。

但是,我们再包一层函数,代码的表现就完全不一样了。

 function test() {
     function foo() {
         var a = 2;
         this.bar();
     }

     function bar() {
         console.log(this.a);
     }
     foo();
 }

 test();

如果this指向函数作用域,那么它就可以通过作用域链获取到test函数下的bar函数,但是结果却是:Uncaught TypeError: this.bar is not a function

仔细看这个报错,他是TypeError;说明查到了this这个变量,但是因为this上没有bar,得到是一个undefined,被运行是出现了类型错误。

所以,我们不能说this就是指向函数作用域,只是因为在某些情况下,表现的像是指向函数作用域。

需要明确的是,this 在任何情况下都不指向函数的词法作用域。每当你想要把 this 和词法作用域的查找混合使用时,一定要提醒自己,这是无法实现的。

this到底是什么?

首先我们需要知道,this是运行时绑定的,并不是在编写时绑定,包括ES6的箭头函数的this,都是运行时绑定的,这点尤为重要。this存储在函数的执行上下文中,而这个上下文的内容取决于函数的调用方式。

this 的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式(也就是运行时)。

当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this 就是活动记录中的一个属性,会在函数执行的过程中用到。

分类: 你不知道的JavaScript 标签: 上下文this

评论

暂无评论数据

暂无评论数据

目录