面试常问的this指向问题

126 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情

1.浅谈对this的理解

this 是一个在运行时才进行绑定的引用,在不同的情况下它可能会被绑定不同的对象。

默认绑定 (指向window的情况) (函数调用模式 fn() )

默认情况下,this 会被绑定到全局对象上,比如在浏览器环境中就为window对象,在node.js环境下为global对象。

如下代码展示了这种绑定关系:

message = "Hello"; 
​
function test () { 
  console.log(this.message); 
}
​
test() // "Hello"

隐式绑定 (谁调用, this指向谁) (方法调用模式 obj.fn() )

如果函数的调用是从对象上发起时,则该函数中的 this 会被自动隐式绑定为对象:

function test() {
    console.log(this.message); 
}
​
let obj = {
  message: "hello,world",
  test: test
}
​
obj.test() // "hello,world"

显式绑定 (又叫做硬绑定) (上下文调用模式, 想让this指向谁, this就指向谁)

硬绑定 => call apply bind

可以显式的进行绑定:

function test() {
    console.log(this.message); 
}
​
let obj1 = {
  message: "你好世界123"
}
​
let obj2 = {
  message: "你好世界456"
}
​
test.bind(obj1)() // "你好世界123"
test.bind(obj2)() // "你好世界456"

new 绑定 (构造函数模式)

另外,在使用 new 创建对象时也会进行 this 绑定

当使用 new 调用构造函数时,会创建一个新的对象并将该对象绑定到构造函数的 this 上:

function Greeting(message) {
    this.message = message;
}
​
var obj = new Greeting("hello,world")
obj.message // "hello,world"

小测试:

let obj = {
    a: {
        fn: function () {
            console.log(this)
        },
        b: 10
    }
}
obj.a.fn()
let temp = obj.a.fn;
temp()
​
// -------------------------------------------------------------function Person(theName, theAge){
    this.name = theName
    this.age = theAge
}
Person.prototype.sayHello = function(){ // 定义函数
    console.log(this)
}
​
let per = new Person("小黑", 18)
per.sayHello()

2. 箭头函数中的this指向什么?

箭头函数不同于传统函数,它其实没有属于⾃⼰的 this

它所谓的 this 是, 捕获其外层 上下⽂的 this 值作为⾃⼰的 this 值。

并且由于箭头函数没有属于⾃⼰的 this ,它是不能被 new 调⽤的。

我们可以通过 Babel 转换前后的代码来更清晰的理解箭头函数:

// 转换前的 ES6 代码
const obj = { 
  test() { 
    return () => { 
      console.log(this === obj)
    }
  } 
}
// 转换后的 ES5 代码
var obj = { 
  test: function getArrow() { 
    var that = this
    return function () { 
      console.log(that === obj)
    }
  } 
}

这里我们看到,箭头函数中的 this 就是它上层上下文函数中的 this