学习JavaScript——this绑定
什么是 this
this
是当前执行上下文(global、function 或 eval)的一个属性。在非严格模式下,总是指向一个对象;在严格模式下可以是任意值。
- 无论是否在严格模式下,在全局执行环境中(在任何函数体外部)
this
都指向全局对象window
。
1 | // 在浏览器中, window 对象同时也是全局对象: |
- 在函数内部,
this
的值取决于函数被调用的方式。非严格模式下,函数内部的this
指向window
;严格模式下,如果进入执行环境时没有设置this
的值,this
会保持为undefined
。
1 | // 非严格模式 |
this
不能在执行期间被赋值。
this 绑定规则
this
绑定有四大规则:默认绑定、隐式绑定、显式绑定、new 绑定。
默认绑定
又可以叫函数调用,在没有其它规则的情况下默认使用的绑定规则,一般就是直接调用函数的情况。默认绑定一般绑定到window
上,严格模式下绑定到undefined
。
1 | function foo() { |
解析:直接调用时,this
指向了window
,所以this.a
其实就是window.a
,而函数外部执行的代码var a = 10
也把a
设置到了window
对象上,所以最后输出的结果为10
。也可以这么认为,foo()
实际调用的是window.foo()
,而 foo 函数内部的this
指向的是window
,所以this.a
指向的是window.a
,也就是10
。
1 | ; |
解析:严格模式下this
指向的是undefined
,所以this.a
实际上访问的是undefined.a
,undefined
上不存在a
,所以会报错。
1 | var a = 10; |
解析:在 ES5 中,能在window
上看到var
命令和function
命令声明的全局变量;在 ES6 中,全局对象的属性和全局变量脱钩,但为了保持兼容性,旧的不变,var
命令和function
命令声明的全局变量依旧可以在window
对象上看到,而let
、const
声明的全局变量在window
对象上看不到,可以直接访问。
隐式绑定
又可以叫对象方法调用,即作为对象方法使用。既然是对象调用,那么就少不了对象的使用。
1 | function foo() { |
解析:foo()
运行时,相当于运行了window.foo()
,函数内部的this
指向的是window
,而window
上并没有属性a
,所以结果为undefined
。obj.foo()
运行时,函数内部的this
指向的是obj
对象,所以this.a
实际上指的是obj.a
,结果为20
。因为函数内部的this.a
指向的是obj.a
,所以给obj.a
赋值为30
,输出的结果也是30
。
显式绑定
显示绑定就是通过内置的call()
、apply()
、bind()
方法来主动改变函数中this
的指向。三种方法的thisObj
如果未传,那么Global
对象被用作thisObj
。
call()
语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]])
。call
从第二个参数开始所有的参数都是原函数的参数。
apply()
语法:apply([thisObj[,argArray]])
。apply
只接受两个参数,且第二个参数必须是数组,这个数组代表原函数的参数列表。
bind()
语法:bind([thisObj[,arg1[, arg2[, [,.argN]]]]])
。bind
只有一个函数,且不会立刻执行,只是将一个值绑定到函数的this
上,并将绑定好的函数返回,因此需要再一次调用。
1 | var o = { |
new 绑定
也叫构造函数调用。语法:new constructor[([arguments])]
。
1 | var a = 0; |
优先级
this 绑定优先级:new 绑定 > 显示绑定 > 隐式绑定 > 默认绑定。
箭头函数的 this 绑定
箭头函数体内的 this 对象,就是定义该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。也就是说箭头函数是根据外部作用域来决定this
的,且箭头函数的this
绑定无法被修改。
1 | function foo() { |
常见面试题
题目 1
1 | var x = 10; |
题目 2
1 | function foo(arg) { |
题目 3
1 | var x = 10; |
题目 4
1 | function foo() { |
题目 4 解析:
1 | function foo() { |