this
是 Javascript 语言的一个关键字。 它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。而这个内部对象 this 指向谁有时却让我们很困惑。在绝大多数情况下,函数的调用方式决定了 this 的值。this 不能在执行期间被赋值,在每次函数被调用时 this 的值也可能会不同。
this 指向谁
Function Invocation Pattern
诸如 foo()
的调用形式被称为 Function Invocation Pattern,是函数最直接的使用形式,注意这里的 foo 是作为单独的变量出现,而不是属性。在这种模式下,foo 函数体中的 this 永远为 Global 对象,在浏览器中就是 window 对象。
|
|
需要注意的是:在严格模式(‘use strict’)中的默认的 this 不再是 window,而是 undefined.
Method Invocation Pattern
诸如 foo.bar()
的调用形式被称为 Method Invocation Pattern,注意其特点是被调用的函数作为一个对象的属性出现,必然会有“.”或者“[]”这样的关键符号。在这种模式下,bar 函数体中的this永远为“.”或“[”前的那个对象,如下面例中就 foo
函数中 this
就是指向 obj
对象。
|
|
Constructor Pattern
new foo()
这种形式的调用被称为 Constructor Pattern,其关键字 new
就很能说明问题,当一个函数被作为一个构造函数来使用(使用new关键字),它的 this
与即将被创建的新对象绑定。如下面例子中,foo
函数内部的 this
永远是 new foo()
返回的对象。
|
|
Apply Pattern
foo.call(thisObject)
和 foo.apply(thisObject)
的形式被称为 Apply Pattern,使用了内置的 call
和 apply
函数。在这种模式下,call
和 apply
的第一个参数就是 foo
函数体内的 this
,如果 thisObject
是 null
或 undefined
,那么会变成 Global 对象。
|
|
this 对象只会在一个函数中需要确定,如果是在全局域下,this 永远为 Global 对象,在浏览器中通常就是 window 对象。
应用以上4种方式,确定一个函数是使用什么样的 Pattern 进行调用的,就能很容易确定 this 是什么。另外,this 是永远不会延作用域链或原型链出现一个“查找”的过程的,只会在函数调用时就可以完全确认。
常见例子
|
|
其中两处调用(1)、(2) 分别输出: 20、10;
- (1):
obj.f()
调用,被调用的函数f
作为obj
对象的属性出现,属于 Method Invocation Pattern,f
函数内的this
指向obj
, 所以f
函数中输出this.x
为20 - (2):
f
函数中调用foo
函数时是作为单独的变量出现,而非某个对象的属性,属于 Function Invocation Pattern,所以其中this
指向全局变量 window, 输出this.x
时找到全局变量中x
的值 10,所以输出为 10
那么如果也希望(2)处调用输出 20,要如何修改呢?👇
|
|
bind 函数和箭头函数
bind 函数
ES5 引入了 bind
方法来设置函数的 this
值,而不用考虑函数如何被调用的。调用 f.bind(someObject)
会创建一个与 f 具有相同函数体和作用域的函数,但是在这个新函数中,this 将永久地被绑定到了 bind 的第一个参数,无论这个函数是如何被调用的。
|
|
箭头函数
箭头函数在设计中使用的是 Lexical this,即这个函数被创建时的所在环境的 this 就是函数内部的 this
|
|
|
|
DOM事件处理函数中的 this
为 DOM 元素添加事件处理函数大致有以下两种方式:
方式一
element.onclick = doSomething;
,函数被用作事件处理函数时,它的this指向触发事件的元素
|
|
在这个例子中,点击 button 之后,会执行其 onclick
事件回调函数 clickHandler
,执行时,函数中的 this
都会指向触发事件的 button 元素(onclick
是 button 元素的一个属性)
方式二
<element onclick="doSomething()">
,在内联事件处理函数中的 this
,并不指向触发事件的元素
|
|
在这个例子中,点击 button 之后,会执行 clickHandler()
函数,这属于 Function Invocation Pattern,所以此时函数中的 this
指向为 windows(严格模式下为 undefined)
如果希望在内联事件处理函数中的 this
也指向该元素,那么我们可以用 bind
函数指定其 this
值。
当然也可以使用
call
或者apply
方法。JavaScript 中的 apply、call、bind
|
|
区别
通过以上两种方式为 DOM 元素添加事件处理函数后,我们可以输出看看:
|
|
方式一输出:
123function clickHandler() {console.log(this.id)}方式二输出:
123function onclick(event) {clickHandler()}
通过以上也很好说明了,前者中的 this
指向触发事件的 DOM 元素;而后者中的 this
指向全局对象 window
总结
通过以上的了解,不同方式为 DOM 元素添加事件处理函数,函数中的 this
指向可能不同,需要特别留意。
通过以下方式添加的事件处理函数,this
都正常指向 DOM 元素:
|
|
而通过以下方式添加的事件处理函数,this
并不指向 DOM 元素:
|
|