JavaScript 中 this 的总结

236 阅读3分钟

一、普通函数的 this

普通函数的 this 可视为一个隐藏参数,为函数内部的私有变量,在函数调用时才绑定 this 的值,在调用前 this 的指向无法确定。

考虑如下函数:

function fn(name){
    console.log(name)
    console.log(this)
}

1、常规调用

常规调用 fn('jack'),这种调用形式没传 this,即 thisundefined ,但在浏览器中this会自动变成 window。在严格模式下,this的值才是undefined

2、用 call 方法调用

用 call 方法调用时,第一个参数会传给 this,后面的是函数真正的参数

fn.call(a, 'jack') //this 会绑定为 a

【注】:若传入的 a 不是对象,会自动转化为对象

3、在对象中调用

考虑如下对象:

const obj = {
    name: 'jack',
    say(){
        console.log(this.name)
    }
}

obj.say() //打印出 'jack'

调用方法 obj.say(),会自动将obj传给this,即obj.say() 等价于 obj.say.call(obj)

4、在数组中调用

数组也是一种对象,在数组中调用函数和在对象中调用一样,this会绑定为当前数组。

const arr = [
    'jack',
    function(){console.log(this)}
]

arr[1]() //打印出 arr

5、用 new 调用构造函数

用 new 调用函数会得到一个对象,在函数中,this 绑定为这个待返回的对象。例:

function fn(name){
    this.name = name
}

const obj = new fn('jack')
obj.name //'jack'

二、箭头函数的 this

箭头函数内部没有 this,它使用的 this 就是箭头函数所在作用域的 this,即箭头函数的 this 在函数创建的时候就已经确定了。

【例1】如下函数:

function fn(){
    const arrowF = ()=>{console.log(this)}
    return arrowF
}

const f1 = fn()
f1() //打印出 window

const f2 = fn.call({})
f2() //打印出空对象 {}
  • 调用 fn() 时,fn 中的 this 绑定为 window ,然后创建箭头函数 arrowF,它内部的 this 就是 window,将这个函数作为返回值赋给 f1。调用f1(),则打印出 window
  • 调用 fn.call({}) 时,fn 中的 this 绑定为 {} ,然后创建箭头函数 arrowF,它内部的 this 就是 {},将这个函数作为返回值赋给 f2。调用f2(),则打印出 {}

【注】:即便用 call 方法调用箭头函数,依然无法改变其 this 的绑定

【例2】尽量不要在对象中使用箭头函数,如:

const obj = {
    name: 'jack',
    say: ()=>{console.log(this.name)}
}

obj.say() //undefined

say 方法为箭头函数,其在定义时 this 就被确定为 window

三、事件监听器中 this 的确定

事件监听器中的this同样由其被调用的方式确定。

1、Event Handler

btn.addEventListener('click', function handler(){console.log(this)})

handler被调用时,其中的this是被监听的元素,相当于传入的event参数的currentTarget属性,可以假定浏览器调用handler的方式为:

handler.call(event.currentTarget, event)

2、jQuery 的 Event Handler

jQuery 调用handler时,this指向当前执行事件的元素。

  • 对于直接事件:
$div.on('click', function handler(){console.log(this)})

this就是被绑定事件的元素,即$div所对应的元素。

  • 对于代理事件:
$ul.on('click', 'li', function handler(){console.log(this)})

this就是被代理的元素,即相应的<li>元素。

3、Vue

Vue 中handlerthis很简单,其指向始终绑定为当前实例/组件。

4、React

React 的类组件中,handler为全局调用,thisundefined,并且使用了严格模式,不会转为window