Javascript系列之this的绑定

77 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情


关于this

this 关键字是javascript中最复杂的机制之一。比如说:在React中我们经常会使用bind将函数绑定在类组件上,或者在JSX直接使用箭头函数调用方法。

当我们编写的方法需要传递对象作为参数时,我们可以使用this来隐式地传递这个对象引用,因此可以将API设计的更加简洁且便于复用。 当我们的设计越来越复杂的时候,显示传递上下文对象会让代码变得越来越混乱。但是隐式传递对象则不会这样。

在接下来让我们全面且详细地复习巩固一下this的绑定规则。


this的绑定

首先this是在运行时绑定的,不是在编写时绑定的,它的上下文取决于函数调用时的各种条件。 this的绑定和函数的声明位置没有任何关系,只取决于函数的调用方式。

1. 默认绑定

function foo(){
    console.log(this.a)
}
var a = 1
foo()

这里毫无疑问会输出:1 我们声明了一个变量a,这个a就是全局对象的一个属性,在浏览器中就等价与window.a = 1,当我们调用foo()时,this.a被解析成了window.a

这里就发生了默认绑定,this指向了全局对象。

在代码中,foo()是直接使用不带任何修饰的函数引用进行调用的,因此只能是默认绑定。

2. 隐式绑定

function foo(){
    console.log(this.a)
}
var obj = {
    a: 2,
    foo: foo
}
obj.foo()

首先我们需要明确foo的声明方式,obj中的foo属性只是引用了这个函数,这个函数并不属于obj对象。但是,调用位置会使用obj上下文引用函数,或者说函数被调用时obj对象拥有这个函数引用。

当函数引用有上下文对象时,隐式绑定规则会把函数中的this绑定到这个上下文对象上。

3. 显式绑定

隐式绑定需要我们在对象上有一个指向函数的属性,并通过这个属性间接调用函数,从而把函数的this隐式绑定到这个对象上。那我们怎么在某个对象上强制调用它不存在的函数呢。

这个时候我们可以使用call()apply()方法进行显示绑定。

function foo() {
    console.log(this.a)
}
var obj = {
    a:3 
}
foo.call(obj)

4. new绑定

function foo(a) {
    this.a = a
}
var bar = new foo(4)
console.log(bar.a)

最终将输出:4。 使用new来调用foo()的时候,我们会构造一个新对象并把它绑定到foo()调用中的this上。这就是new绑定。

this绑定优先级

如何判断一个运行中函数的this绑定, 需要找到函数的直接调用位置,之后按照下面顺序判断this的绑定对象

  1. new调用:绑定到新创建的对象
  2. callapplybind调用: 绑定到指定对象
  3. 由上下文对象调用:绑定到上下文对象
  4. 默认:在严格模式下绑定到undefined, 否则绑定到全局对象