你不知道的JS系列 ( 18) - this 的错误认识
第一种误解:this 理解成指向函数本省,函数看作一个对象,this 并不像我们所想的那样指向函数本身。
function foo(num){ console.log('foo: ' + num); this.count++; } foo.count = 0; var i; for(i=0; i<10; i++){ if (i > 5) { foo(i); } } console.log(foo.count); // 0
foo 确实被调用了 4 次,但是 foo.count 仍然是 0.显然从字面意思来理解 this 是错误的。如果我增加的 count 属性和预期不一样,那么增加的是哪个 count?实际上,如果深入探索的话,就会发现这段代码在无意中创建了一个全局变量,它的值是 NaN。那我们如何解决这个问题?
function foo(num){ console.log('foo: ' + num); // 记录 foo 被调用的次数 data.count++; } var data = { count: 0 } var i; for(i=0; i<10; i++){ if (i > 5) { foo(i); } } console.log(data.count); // 4
从某种角度来说这个方法确实解决了问题,但可惜它忽略了真正的问题——无法理解 this 的含义和工作原理——而是返回舒适区,使用了一种更熟悉的技术,词法作用域
function foo(num){ console.log('foo: ' + num); // 记录 foo 被调用的次数 foo.count++; } foo.count = 0; var i; for(i=0; i<10; i++){ if (i > 5) { foo(i); } } console.log(foo.count); // 4
然而,这种方法同样回避了 this 的问题,并且依赖于变量 foo 的词法作用域
function foo(num){ console.log('foo: ' + num); this.count++; } foo.count = 0; var i; for(i=0; i<10; i++){ if (i > 5) { foo.call(foo, i); } } console.log(foo.count); // 4
这次我们接受了 this,没有回避它。
第二种误解:this 指向函数的作用域。在某种情况下它是正确的,但明确的是,this 在任何情况下都不指向函数的词法作用域。
function foo() { var a = 2; this.bar(); } function bar(){ console.log(this.a); } foo(); // undefined
这段代码非常完美的展示了 this 多么容易误导人。首先 this.bar() 来引用 bar() 函数。这是绝对不可能成功的。调用 bar() 最自然的方法是省略前端的 this。此外,开发者试图使用 this 联通 foo() 和 bar() 的词法作用域。每当你想要把 this 和词法作用域的查找混合使用时,一定要提醒自己,这是无法实现的。
学习 this 的第一步是明白 this 既不指向函数自身也不指向函数的词法作用域。
this 是在运行时进行绑定的,并不是在编写时绑定。this 的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。