本文章通过代码的运行来形容 this 的具体指向:
默认绑定
场景一:
console.log('一般状况', this) // window
在一般状态下, this 指向的是全局变量 window
场景二:
function foo() {console.log('一般函数体', this)}
foo() // window
在函数体内, this 也是指向全局变量 window
论断一:
在失常, 无任何调用的状况下, this 是指向全局变量 window 的
隐式绑定:
场景三:
function get() {console.log(this.a);}
var obj = {a: 2, get}
obj.get() // 2
在 obj.get 调用下, get 中 this 指向的就是 obj 这个对象
场景四:
var obj2 = {obj, a: 1}
obj2.obj.get() // 2
能够看到, 只管有二层调用, this 指向的还是最近一层中的 this
论断二
从而得出, this 他所在的函数被调用了, 那么他就会指向该函数, 并且会指向他最近的一个调用对象
this 失落的状况:
此种状况是针对 论断二
的有余所作出的补充
场景五:
function get() {console.log(this.a);}
var obj = {a: 2, get}
// 更换调用形式:
var getIns = obj.get
getIns() // undefined
如果调用对象被赋值, 在指向之后他其实是并没有调用对象的, 当然他也不会指向 window, 所以 this 指向的是 unde
场景六:
var o1 = {text: 'o1', fn: function () {return this.text}}
var o3 = {text: 'o3', fn: function () {console.log('o3', this) var fn = o1.fn return fn()}}
console.log('o3 失落 this 的状况', o3.fn()) // undefined
能够看到 即便在 o3 中的 fn 里被调用, this 仍旧是处于空的指向
此场景是为了增强场景五所作出的验证
论断三:
如果调用对象被赋值后调用, 如果没有绑定 this, 那么他的指向将会失落
为什么会失落
起因的话, 等你看完这篇文件, 大抵能够明确了: http://www.ruanyifeng.com/blo…
显示绑定
场景七:
var getIns = obj.get.bind(obj)
getIns() // 2
套用情景 5 this 失落的场景, 能够看到, 当初打印的是咱们想要的值了
场景八:
var o3 = {text: 'o3', fn: function () {var fn = o1.fn return fn.call(this) }}
console.log('情景 8 o3 失落 this 的状况批改', o3.fn()) // undefined
该场景应用 call/apply
这两个函数的作用是一样的, 惟一不一样在于传参:call(this,1,2,3)
apply(this, [1,2,3])
apply 这些函数非凡的中央:
var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.log(array); // ["a", "b", 0, 1, 2]
通过 apply 间接 push 了多个参数
在 es6 之后 也快应用这种形式: array.push(...elements)
场景九:
class Foo {
name = "mike"
say() { console.log(this.a) }
}
var FooIns = new Foo()
FooIns.say() // undefined
class 中的函数, 这也属于一种 this 失落的场景
相熟 react 的人应该就晓得这个场景
new 绑定
这里说的 new 绑定和情景 9 是不一样, 说的是构造函数的绑定:
场景十
// es5 代码
function Foo2() {this.bar = "LiLz"}
const Foo2Ins = new Foo2()
console.log(Foo2Ins.bar) // LiLz
在下面情景一中 this 指向的是 window, 在场景 10 中, 通过 new 胜利将 this 绑定在了 Foo2Ins 上
场景十一
class Foo3 {constructor() {this.bar = 'lisa'}}
var Foo3Ins = new Foo3()
console.log(Foo3Ins.bar) // lisa
从这里能够看到 new 的作用, 尽管扭转指向只是他的一部分性能
论断四
隐式 / 显示调用能够扭转 this 指向, 而且比隐式调用的优先级要大
非凡状况 - 严格模式
场景十二
function foo2() {'use strict' console.log('严格模式下的 this', this)
}
foo2() // undefined
能够看到在严格模式下 一般的 this 指向就是会失落
非凡状况 - 箭头函数
咱们来看看箭头函数对应的 this 有什么区别
场景十三
const bar = () => {'use strict' console.log('箭头函数', this)}
bar() // windows
即便在严格模式下 箭头函数中的 this 也不会是 undefined
场景十四
const get2 = () => {console.log(this, this.a);}
var obj3 = {a: 2, get2}
obj3.get2() // window, undefined
隐式调用无奈扭转其指向
场景十五
obj3.get2.bind(obj3)() // 同场景 14
obj3.get2.call(obj3) // 场景 14
论断五
这里能够得出结论, 隐式 / 显示调用都不能扭转箭头函数的指向
场景十六
const Foo4 = () => { this.bar = "LiLz"}
const Foo4Ins = new Foo4()
console.log(Foo4Ins.bar) // TypeError: Foo4 is not a constructor
遇到 new 时, 能够看到箭头函数, 他是无奈被作为构造函数的
场景十七
class Foo5 {
name = "mike"
say = () => { console.log(this.name) }
}
var Foo5Ins = new Foo5()
Foo5Ins.say() // mike
论断六
至此能够得出 this 扭转的权重: 箭头函数 = new > bind/apply/call > 函数调用
总结:
- 在失常, 无任何调用的状况下, this 是指向全局变量 window 的
- this 他所在的函数被调用了, 那么他就会指向该函数, 并且会指向他最近的一个调用对象
- 如果调用对象被赋值后调用, 如果没有绑定 this, 那么他的指向将会失落
- 隐式 / 显示调用能够扭转 this 指向, 而且比隐式调用的优先级要大
- 隐式 / 显示调用都不能扭转箭头函数的指向, 箭头函数与 new 的构造函数相矛盾
- this 扭转的优先级: 箭头函数 = new > bind/apply/call > 函数调用
本文中的所有例子都在 GitHub 中: https://github.com/Grewer/JsD…