在 JavaScript 中,this 是当前执行函数的上下文。因为 JavaScript 有4种不同的函数调用方式:
函数调用: alert(‘Hello World!’)
方法调用: console.log(‘Hello World!’)
构造函数调用: new RegExp(‘\d’)
隐式调用: alert.call(undefined, ‘Hello World!’)
函数调用指执行构成一个函数的代码(简单说就是 call 一个函数)例如 parseInt(‘15’)是 parseInt 函数调用.
函数调用的上下文指 this 在函数体中的值。 即 this指的是调用函数的那个对象,例:object.fn(),这里的 this 便是 object。
函数的作用域指的是在函数体内可以使用的变量、对象以及函数的集合。
函数调用
|
|
更加高级的例子是 IIFE (立即调用的函数表达式):
IIFE 也是一个函数调用: 第一对括号(function(name) {…}) 是一个等价于函数的表达式, 紧接着一对括号以及’World’参数: (‘World’)
函数调用中的this
this 在函数调用中是一个全局对象
全局对象是由执行的环境决定的。在浏览器里它是window对象。
在函数调用里,函数执行的上下文是全局对象。让我们一起看看下面函数里的上下文:
|
|
函数调用中的 this, strict 模式
strict 模式下,函数调用中的 this 是 undefined
为了使用它,把’use strict’放在函数体的开始。这个模式会影响执行的上下文,把 this 变成 undefined。函数执行的上下文跟上面的例子相反,不再是全局对象
在strict模式下执行函数的例子:
当 multiply(2, 5) 作为函数被调用时,this 是 undefined。
strict 模式不仅在当前作用域起作用,也会对内部的作用域起作用(对所有在内部定义的函数有效):
‘use strict’ 插入在 execute 函数体的一开始, 使它在 execute 函数的作用域内起作用。 因为 concat 定义在 execute 的作用域内, 它也会继承 strict 模式,
这导致调用 concat(‘Hello’, ‘ World!’)时, this 是 undefined。
单个的JavaScript文件可能既包含 strict 模式又包含 非strict 模式。所以,在单个的脚本内,同样的调用方法可能有不同的上下文行为:
陷阱: 内部函数中的this
一个函数调用中的常见错误就是以为 this 在内部函数中跟在外部函数中一样。 正确来说,内部函数的上下文依赖于调用方法,而不是外部函数的上下文。
为了能使 this 跟预期的一样,用隐式调用来修改内部函数的上下文 (用.call()或者.apply()) 或者创建一个绑定函数 (用.bind())
下面的例子计算了2个数字的和:
numbers.sum() 是一个对象上的方法调用 ,所以 sum 中的上下文是 numbers 对象。calculate 函数定义在 sum 内部,所以你会指望 calculate()
中的 this 也是 numbers 对象。然而,calculate() 是一个函数调用(而不是方法
调用),它的 this 是全局对象 window 或者 strict 模式下的 undefined。即使外部函数 sum 的上下文是 numbers对象,它在这里也没有影响。numbers.sum()的调用结果是NaN或者
strict 模式下的 TypeError: Cannot read property ‘numberA’ of undefined 错误。因为 calculate 没有被正确调用,结果绝不是预期的 5 + 10 = 15。
为了解决这个问题,calculate应该跟sum有一样的上下文,以便于使用numberA和numberB。解决方法之一是使用.call()方法
calculate.call(this) 像往常一样执行 calculate,但是上下文由第一个参数指定。现在 this.numberA + this.numberB 相当于 numbers.numberA + numbers.numberB,函数会返回预期的结果 5 + 10 = 15。
深入了解更多参阅:http://www.w3cplus.com/javascript/gentle-explanation-of-this-in-javascript.html