关于this
为什么会有this
this在JavaScript中是一个非常复制的机制,它的存在其实是为了能让我们更好的复用代码,this提供了一种更优雅的方式来隐式“传递”一个对象引用,因此可以将API设计的更加简洁且易于复用。
我们举个例子:
new一个构造函数,我们可以得到一个新的实例对象,这个对象会继承原型,此时,如果没有this,如何在原型方法里去访问你的新的实例对象,以及获取属性这些操作。
显然是不太好做的,难道每次都把自身作为参数传递给prototype上的方法吗?
显然这非常不方便,如果使用了this,this会指向这个新的实例对象,那么我们在书写代码是就会更加方便了,复用也更加简单。
这个this不需要自己去声明,减少了大量啰嗦代码。
this的误区
如果不熟悉this到底是如何工作的,或者局限于字面的译意,很容易会产生误解,常见的两种错误认为:
- this指向自身
- 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 就是活动记录中的一个属性,会在函数执行的过程中用到。
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据