ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 2.1 关于this ### 2.1.1 为什么要用this ~~~ function identify() { return this.name.toUpperCase(); } function speak() { var greeting = "Hello, I'm " + identify.call(this); console.log(greeting); } var me = { name: "Kyle" }; var you = { name: "Reader" }; identify.call(me); // KYLE identify.call(you); // READER speak.call(me); // Hello, 我是KYLE speak.call(you); // Hello, 我是 READER ~~~ 如果不使用this,那就需要给identify() 和speak() 显式传入一个上下文对象。 ~~~ function identify(context) { return context.name.toUpperCase(); } function speak(context) { var greeting = "Hello, I'm " + identify(context); console.log(greeting); } identify(you); // READER speak(me); //hello, 我是KYLE ~~~ ### 2.1.2 误解 **1. 指向自身** ~~~ 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 -- ??? ~~~ console.log 语句产生了4 条输出,证明foo(..) 确实被调用了4 次,但是foo.count 仍然是0。显然从字面意思指向函数自身来理解this 是错误的。 如果要从函数对象内部引用它自身,那只使用this 是不够的。一般来说需要通过一个指向函数对象的词法标识符(变量)来引用它。 思考一下下面这两个函数: ~~~ function foo() { foo.count = 4; // foo 指向它自身 } setTimeout( function(){ // 匿名(没有名字的)函数无法指向自身 }, 10 ); ~~~ 第一个函数被称为具名函数,在它内部可以使用foo 来引用自身。但是在第二个例子中,传入setTimeout(..) 的回调函数没有名称标识符(这种函数被称为匿名函数),因此无法从函数内部引用自身。 另一种方法是强制this 指向foo 函数对象: ~~~ function foo(num) { console.log("foo: " + num); // 记录foo 被调用的次数 // 注意,在当前的调用方式下(参见下方代码),this 确实指向foo this.count++; } foo.count = 0; var i; for (i = 0; i < 10; i++) { if (i > 5) { // 使用call(..) 可以确保this 指向函数对象foo 本身 foo.call(foo, i); } } // foo: 6 // foo: 7 // foo: 8 // foo: 9 // foo 被调用了多少次? console.log( foo.count ); // 4 ~~~ **2. this指向函数的词法作用域** **this 在任何情况下都不指向函数的词法作用域。**在JavaScript 内部,作用域确实和对象类似,可见的标识符都是它的属性。但是作用域“对象”无法通过JavaScript代码访问,它存在于JavaScript 引擎内部。 ~~~ function foo() { var a = 2; this.bar(); } function bar() { console.log( this.a ); } foo(); // ReferenceError: a is not defined ~~~ 以上代码试图(但是没有成功)跨越边界,使用this 来隐式引用函数的词法作用域。 * 首先,这段代码试图通过this.bar() 来引用bar() 函数。这是绝对不可能成功的。(调用bar() 最自然的方法是省略前面的this,直接使用词法引用标识符。) * 此外,还试图使用this 联通foo() 和bar() 的词法作用域,从而让bar() 可以访问foo() 作用域里的变量a。这是不可能实现的,你不能使用this 来引用一个词法作用域内部的东西。 **3. this到底是什么** this 是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件。**this 的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。** 当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this 就是记录的其中一个属性,会在函数执行的过程中用到。