[js基础04]javascript令人头痛的this绑定 |8月更文挑战

206 阅读3分钟

[js基础04]javascript令人头痛的this绑定

js中作用域是词法作用域,可以说其是静态的,在代码调用前确定。我们在分析作用域链,变量属于哪个作用域的时候就十分的明确。

而对于this绑定来说,这个在函数调用的时候才能确定。在日常工作中,我们经常会遇到this相关的bug,面试过程中中,也会有人问我们this绑定的机制。 曾今一段时间this绑定一度成为我一个头痛的问题。

函数的身份

函数是js中的一等对象,很多书籍又把函数称为一等对象。函数在程序中根据其调用的场景,他可以有以下身份。

  1. 包裹一段逻辑代码,作为一个函数被调用
function add(a, b) {
    return a + b
}
  1. 作为一个对象的方法进行调用
var obj = {
    a: 1,
    b: 2,
    add: function() {
        return this.a + this.b
    }
}
obj.add()
  1. 作为构造函数被调用
function Person(name, age) {
  this.name = name
  this.age = age
  console.log(this)
}
var person = new Person('小华', 18)
  1. 使用call,apply调用
var obj = {
    a: 1,
    b: 1
}
function add() {
    return this.a + this.b
} 

作为函数被调用

函数作为函数被调用有一点拗口,其实你可以理解为这个函数就包裹了一段逻辑代码,他不作为构造函数、不作为方法、不使用call调用

var a = 1 
var b = 2
function add() {
    return this.a + this.b
}
add() // 3

浏览器环境下会输出3。在这种规则下,this指向全局对象window, var a = 1,var b = 2等于在window对象上添加ab属性并对其赋值,所以this.a = window.a,this.b = window.b

作为方法被调用

var obj = {
    a: 1,
    b: 2,
    add: function() {
        return this.a + this.b
    }
}
obj.add()

此规则下,this会指向这个对象,也就是obj。此时this.a = obj.a, this.b = obj.b

引用陷阱

var a = 1
var b = 2

var obj = {
    a: 2,
    b: 3,
    add: function() {
        return this.a + this.b
    }
}

var test = obj.add
test() // 3 而不是 5

把一个对象的方法赋值给一个变量,再进行调用。此时是作为一个函数被调用

call/apply调用

var obj = {
    a: 1,
    b: 1
}
function add() {
    return this.a + this.b
} 
add.call(obj)

强制给函数绑定上下文,此时的this等于call的一个参数。

call绑定null或者undefined


var a = 1
var b = 2

function add() {
  return this.a + this.b
} 
add.call(null) // 3
add.call(undefined) //3
add.call() // 3

以上三种情况都会输出3。说明此时的this会绑定到全局变量

作为构造函数被调用

function Person(name, age) {
  this.name = name
  this.age = age
  console.log(this) // 此时为mjg
}
var mjg = new Person('小华', 18)

new 操作会返回一个新对象,此时的this就是那个新对象

优先级

最后我们来看看优先级。

  1. 函数是否在 new 中调用(new 绑定)?如果是的话 this 绑定的是新创建的对象。
  2. 函数是否通过 call、apply调用?如果是的话,this 绑定的是指定的对象。
  3. 函数是否作为对象方法被调用?如果是的话,this 绑定的是当前对象。
  4. 如果都不是的话,函数作为函数被调用,绑定全局对象。

尾声

以上的测试代码都在浏览器环境下进行。掌握以上的规则,对于百分之90的this绑定问题都能分析出来。不过对于箭头函数的this我们后续再谈