个人对于this绑定的一些理解

204 阅读2分钟

1. this 绑定的几种方式

  • 默认绑定
  • 隐式绑定
  • 显式绑定
  • bind绑定

2. 例题剖析

2.1 案例一

var name = 'window'
var person1 = {
  // {} 对象或者是函数,对象中是没有 this 的,只有作为函数时才有 this
  name: 'person1',
  foo1: function () {
    console.log(this.name)
  },
  foo2: () => console.log(this.name),
  foo3: function () {
    return function () {
      console.log(this.name)
    }
  },
  foo4: function () {
    // console.log(this) // 第一个表达式this -> person1
    // console.log(this) // 第一个表达式this -> person2
    // console.log(this) // 第一个表达式this -> person1
    return () => {
      console.log(this.name)
    }
  }
}

var person2 = { name'person2' }  
  
person1.foo1();   // 隐式绑定 person1
// 可以这样写的前提是非箭头函数
// 由于 call 方式显式绑定高于隐式绑定,所以可以写成 person2.foo1()
person1.foo1.call(person2);   // 显式绑定 person2
  
// 箭头函数不绑定 this,所以 this 会从上层作用域查找
person1.foo2();  // 上层作用域 window
person1.foo2.call(person2);  // 上层作用域 window
  
 // person1.foo3() 执行结果是一个函数, 虽然有绑定 person1,但是是独立函数调用
person1.foo3()();  // window
person1.foo3.call(person2)();  // window
// 不妨记内层函数为 bar,所以 person1.foo() = bar,即为bar.call(person2),普通函数绑定this
person1.foo3().call(person2);  // person2
  
// person1.foo() 执行会隐式绑定 person1
// 箭头函数内部不绑定 this,会从上层作用域中查找
person1.foo4()();  // person1
// 可以看成是 person2.foo()()
person1.foo4.call(person2)();   // person2
person1.foo4().call(person2);   // person1

2.2 案例二

var name = 'window'  
function Person (name) {  
  this.name = name  
  this.foo1 = function () {  
    console.log(this.name)  
  },  
  this.foo2 = () => console.log(this.name),  
  this.foo3 = function () {  
    return function () {  
      console.log(this.name)  
    }  
  },  
  this.foo4 = function () {  
    return () => {  
      console.log(this.name)  
    }  
  }  
}  

/**
 * 1. 创建一个空的对象
 * 2. 将这个空的对象赋值给 this
 * 3. 执行函数体中代码
 * 4. 将这个新的对象默认返回
 */
var person1 = new Person('person1')  
var person2 = new Person('person2')  
  
person1.foo1()  // 隐式绑定:person1
person1.foo1.call(person2)  // 显式绑定:person2
  
// person1.foo.call(undefined) 箭头函数不绑定 this,上层作用域是 person1
person1.foo2()  // person1
person1.foo2.call(person2)  // person1
  
person1.foo3()()  // 独立函数调用 window
person1.foo3.call(person2)()  // window
person1.foo3().call(person2)  // person2
  
person1.foo4()()  // person1
person1.foo4.call(person2)()  // person2
person1.foo4().call(person2)  // person1

2.3 案例三

var name = 'window'

function Person(name) {
  this.name = name
  this.obj = {
    name: 'obj',
    foo1: function () {
      return function () {
        console.log(this.name)
      }
    },
    foo2: function () {
      // console.log(this) -> 第一个表达式 obj
      // console.log(this) -> 第二个表达式 person2
      return () => {
        console.log(this.name)
      }
    }
  }
}
var person1 = new Person('person1')
var person2 = new Person('person2')

person1.obj.foo1()() // 独立函数调用:window
person1.obj.foo1.call(person2)() // 独立函数调用:window
// foo1 是一个普通函数,所以后面的显式绑定是有效的
person1.obj.foo1().call(person2) // 显式绑定:person2

person1.obj.foo2()() // 上层作用域:obj
person1.obj.foo2.call(person2)() // 显式绑定:person2
// 箭头函数不绑定 person2,会去上层作用域查找
person1.obj.foo2().call(person2) // 上层作用域:obj

PS: 案例二的内存图

image.png