参考
阮一峰
老师对于this的原理理解
一:this的定义
在严格模式下
和非严格模式下
,this
的在全局中会有差别
来自阮一峰
老师对于this的由来的理解
由于函数可以在不同的运行环境中运行,所以需要一种机制,能够在函数的内部获取当前运行环境,因此this就出现来,
this
的设计目的就是为了在函数的内部,指代函数当前的运行环境
所以在绝大多数的情况下,函数当前的运行环境
决定了this
的值
例如:
1 | var obj = { |
- 对于
obj.foo()
来说,是通过obj
这个对象来找到foo()
,所以foo()
的运行环境obj
对象,因此this
的值就是Obj对象 - 对于
foo()
来说,foo()函数的运行环境是window,因此this的值就是window
二:绑定规则
根据不同的使用场合,this
有不同的值,主要分为下面几种情况:
- 默认绑定
- 隐式绑定
- new绑定
- 显示绑定
1. 默认绑定
默认绑定的意思就是,当函数独立执行,不作为一个对象的方法调用时,
this
绑定到全局对象中,但在严格模式下,this
会绑定到undefined
1 | function foo () |
2. 隐式绑定
当函数作为对象的方法调用时,
this
绑定到调用该方法的对象
1 | var obj = { |
这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,
this指向的也只是它上一级的对象
1 | var obj = { |
foo执行的环境是a对象,所以this指向a对象
再例如:
1 | var obj = { |
在该代码中,定义了一个变量
fn
,被将其赋值为obj.a.foo
,这意味着fn
现在引用了,obj对象中,a属性的foo方法。最后调用
fn()
,执行foo()
函数将
obj.a.foo
复制给fn
,只是将foo
函数的引用复制给了fn
,但并没有立即执行。所以fn
只是函数的引用,它的上下文还是跟obj.a.foo
相关但是当调用
fn()
时,这才是真正执行foo
函数的时候,但由于fn
是在全局上下文中调用的,JS将函数上下文this
赋值为window
3. 显示绑定
使用
call()
、apply()
或bind()
方法显式地指定函数的this
值。
1 | var obj = { |
4. new 绑定
当函数用作构造函数(使用
new
关键字创建对象)时,this
绑定到新创建的对象。
1 | function fn () |
- 通过
new
关键字改变了this的执行,指向了obj
当函数返回一个对象
1 | function fn () |
- 当函数返回一个对象时,通过new关键字将this指向改变指向返回的对象,不指向obj
当返回一些简单类型时候
1 | function fn () |
- this还是指向obj
返回null
1 | function fn () |
- 虽然null是object类型
- 但是还是指向obj
三:箭头函数
JS中箭头函数与普通函数在
this
上有着重要的不同。箭头函数
this
的绑定是在箭头函数创建的时候就确定的好的,是静态this
绑定,它没有自己的上下文,它会捕获最近的普通函数的this
值普通函数
this
值取决于,函数是如何被调用的,是根据调用方式动态
确定的
在全局上下文中
1 | var a = 1 |
fn
箭头函数会自动捕获最近的最近的普通函数上下文,通常是全局对象window
在对象方法中
1 | var a = 10 |
fn
箭头函数的this值不取决于被调用时动态绑定,而是在静态创建时候,与最近最近的普通函数上下文this
值一致fn
箭头函数最近最近的普通函数上下文是window全局- 因此
this
指向window
作为事件回调
1 | <button id="btn">点击</button> |
1 |
|
- 点击按钮输出还是10
- 箭头函数作为回调函数时,其
this
绑定通常与定义它的上下文相同。
四:优先级
1. 隐式绑定 VS 显示绑定
1 | function foo() { |
- 显示绑定优先级要高于隐式绑定
2. new绑定 VS 显示绑定
1 | function Person(name) { |
new
绑定的优先级更高。当使用new
关键字创建对象实例时,它会覆盖之前的显式绑定