一、this的四种绑定方式
1.默认绑定
1.非严格模式
- 函数独(普通函数)立调用时,this指向全局对象(浏览器指向window,node指向global)
function fun() {
console.log(this)
}
fun() //window
- 对象的方法调用时,this指向调用该方法的对象
const obj = {
name: "张三",
fun() {
console.log(this)
}
}
obj.fun() //obj
- 杯全剧变量引用时,this指向全局对象
const obj2 = {
fun() {
console.log(this)
}
}
const fun2 = obj2.fun
fun2() //window
- 闭包调用时,this指向全局对象
const obj3 = {
bar: function () {
return function () {
console.log(this)
}
}
}
obj3.bar()() // window
- script 标签中,this指向全局对象(无论是严格模式还是非严格模式)
2.严格模式
- 函数独立(普通函数)调用时,this指向undefined
- 对象的方法调用时,this指向调用该方法的对象
- 全局变量引用时,this指向undefined
- 闭包调用时,this指向undefined
- script 标签中,this指向undefined
2. 隐式绑定
对象的方法是对另一个函数的引用,当调用这个方法时,this指向这个对象
function foo() {
console.log(this)
}
const obj1 = {
name: 'obj1',
foo: foo
}
obj1.foo()
const obj2 = {
name: 'obj2',
bar: function () {
console.log(this)
}
}
obj2.bar()
const obj3 = {
name: 'obj3',
baz: obj2.bar
}
obj3.baz()
3.显式绑定
1.call
function fun() {
console.log(this)
}
fun.call({name: "张三"}) //{name: "张三"}
2.apply
function fun() {
console.log(this)
}
fun.apply({name: "张三"}) //{name: "张三"}
3.bind
function fun() {
console.log(this)
}
const fun2 = fun.bind({name: "张三"})
fun2() //{name: "张三"}
4. new 绑定
函数访问this,如果使用new调用,this指向新创建的对象 class 定义的类,new调用时,this指向新创建的对象两者类似
function Student () {
console.log(this)
}
new Student() //Student {}
class Student {
constructor() {
console.log(this)
}
}
new Student() //Student {}
二、this指向的优先级
1.new 关键字 (优先级最高)
new 关键字调用函数生成对象时,this一定指向新创建的对象,这一点是无法被改变的,尽管使用显示绑定函数去主动绑定this,也无法改变this指向。
2.显示绑定 (优先级极高)
使用call、apply、bind绑定this,this指向绑定对象,这个方式制定this优先级方式极高。且只会在new关键字调用函数时失效。
3.隐式绑定 (优先级较高)
对象的方法调用时,this指向调用该方法的对象,这个方式制定this优先级方式较高。
4.默认绑定 (优先级较低)
函数独立调用时,this指向全局对象,这个方式制定this优先级方式较低。
三、 特殊情况
1.箭头函数
箭头函数本作用域内是没有this的,在箭头函数中访问this,会沿着作用域链向上级作用域中查找this,直到找到为止。
const obj = {
fun: () => {
console.log(this)
}
}
obj.fun() //window
2. 显示绑定特殊值
显示绑定特殊值null,undefined时,this指向绑定不会生效,this会指向全局对象。但是在严格模式下,显示绑定就会生效。
function fun() {
console.log(this)
}
fun.call(null) //window
fun.call(undefined) //window
'use strict'
function fun() {
console.log(this)
}
fun.call(null) // null
fun.call(undefined) // undefined
3. 间接函数引用 (最没有想到的一种)
const obj = {
fun() {
console.log(this)
}
}
const obj2 = {
fun2: obj.fun
}
obj2.fun() //obj2
(obj2.fun2 = obj.fun)() // window
(obj2.fun2 = obj.fun)
返回的是函数本身,所以函数独立调用时,this指向全局对象。
但注意,这个表达式有可能会出现变量提升的问题,是否出现取决于obj.fun
的声明方式,如果obj.fun 是普通函数,那么会出现变量提升,如果obj.fun 是箭头函数,那么不会出现变量提升。
总结
基于以上的分析,我们可以简单的得出this指向简单记忆方式
- script 标签中,this指向全局对象
- 函数作用域中,this指向函数调用对象,如果函数独立调用会出现特殊情况(严格模式指向undefined,非严格指向全局)
- 箭头函数中,this指向会沿着作用域链向上级作用域中查找this,直到找到为止。
- new 关键字调用函数生成对象时,this一定指向新创建的对象,这一点是无法被改变的,尽管使用显示绑定函数去主动绑定this,也无法改变this指向。
- 使用call、apply、bind绑定this,this指向绑定对象,这个方式制定this优先级方式极高。且只会在new关键字调用函数时失效。且如果绑定的是null,undefined时会出现特殊情况(严格模式正常,非严格模式指向全局)
在分析this指向时更加关注这个this所在的作用域,所在的函数是被谁调用的,是否是严格模式等等问题。