前言
与python等其他的编程语言相比,this 关键字在 JavaScript 中的表现有所不同,是否是严格模式也会影响this的绑定;这里面套路众多,一不小心就可能出错,而且this作为动态作用域的表亲,与JavaScript的词法作用域差别很大,因此很多人称它为JavaScript的一个大坑。(我也是这样认为的,2333)
在绝大多数情况下,函数的调用方式决定了this的值。this不能在执行期间被赋值,并且在每次函数被调用时this的值也可能会不同。在此我们主要讨论一下较为常见的几种调用方式和在ES6中的箭头函数中的this。
注:这篇文章是我写的最早的文章之一了是个笔记,因此有点啰嗦和局限性,看完《你不知道的JavaScript》后,总结起来this大致也就四种情况:
- 默认绑定(window)
- 隐式绑定(对象的方法)
- 显示绑定(call,apply,bind)
- new绑定
优先级自下而上。而且在平常日常开发中也尽量少用this(少用,不代表不用),以免在他人(或者很久以后的自己)在维护代码的时候理解错误~(箭头函数是个好东西)
几种较为常见的调用方式:
1.在全局范围内使用this,它将会指向全局对象即window.
1 | var a = 1; |
2.在函数中调用时,也会指向全局对象。而在node中则指向global:
1 | var a = 1; |
要注意的是在ES5的严格模式下,不存在全局变量。this将保持他进入执行上下文时的值,这种情况下this将会是undefined:
1 |
|
3.方法调用text.foo(); 在这个例子时this指向text对象。要注意的是这样的行为,根本不受函数定义方式或位置的影响。而且this 的绑定只受最靠近的成员引用的影响
1 | var text = { |
4.当一个函数用作构造函数时,它的this就会被绑定到正在构造的新对象中:
1 | function Person(age){ |
5.当使用call或者apply方法时,函数内的this将会被显式设置为函数调用的第一个参数。
1 | //对象也可以作为call和apply传入的第一个参数,且this会显式的设置为该对象 |
用 call 和 apply 函数的时候还要注意,如果传递给 this 的值不是一个对象,JavaScript 会尝试使用内部 ToObject 操作将其转换为对象。
6.调用obj.bind()时可以创建一个与obj有着相同函数体和作用域的函数,但this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。
1 | var obj = {name: 'Jake'}; |
7.原型链中的 this仍然指向调用它的对象,这很好理解:
1 | var fn = { |
8.当函数被用作事件处理函数时,它的this指向触发事件的元素:
1 | // 被调用时,将关联的元素变成蓝色 |
箭头函数
由于this的高复杂性,this绑定也成为了JavaScript中最常出错的因素之一。因此在ES6中的箭头函数没有了this绑定,必须通过查找作用域链来决定其值,而在全局代码中,它将被设置为全局对象:
1 | var obj = this; |
由于箭头函数不绑定this,所以 call() / apply() / bind() 方法对于箭头函数来说只是传入参数,对它的 this毫无影响。
1 | //接着上面的代码 |
考虑到 this 是词法层面上的,严格模式中与 this 相关的规则都将被忽略。(可以忽略是否在严格模式下的影响)
1 | var a = () => {'use strict'; return this}; |
而当箭头函数作为方法调用时,this会是怎样的呢?
1 | var obj = { |
可以看到的是作为方法的箭头函数this指向全局对象(window),而普通函数中的this则指向调用它的对象。