this的指向问题汇总

168 阅读3分钟

this的指向有以下几条规律

  1. 在函数体中,非或隐式地简单调用函数时,在严格模式下,函数内的this会被绑定到undefined上,在非严格模式下则会被绑定到全局对象window/global上。
  2. 一般使用new方法调用构造函数时,构造函数内的this会被绑定到新创建的对象上。
  3. 一般通过call/apply/bink方法显式调用函数时,函数体内的this会被绑定到指定参数的对象上。
  4. 一般通过上下文对象调用函数时,函数体内的this会被绑定到该对象上。
  5. 在箭头函数中,this的指向是由外层(函数或全局)作用域来决定的。

一、全局环境中的this

function f1(){
  console.log(this);
}
function f2(){
  'use strict'
  console.log(this);
}
f1() //window
f2() //undefined

上面的比较基础,函数在全局环境中被简单调用,在非严格模式下this指向window,在通过 use strict 指明严格模式的情况下指向undefined。但是要注意它的变种

const foo = {
  bar:10,
  fn:function(){
    console.log(this);
    console.log(this.bar);
  }
}
var fn3 = foo.fn
fn3() //window,undefined

//还是上面这题:如果将调用改为下面这种形式

foo.fn()  //{bar: 10, fn: ƒ}    10

二、上下文对象调用中的this

const student ={
  name:'Mike',
  fn:function(){
    return this
  }
}
console.log(student.fn() === student);  //true

当存在更复杂的调用关系时,如以下代码中的嵌套关系,this会指向最后调用它的对象,因此输出将会是Mike

const person = {
  name:'Lucas',
  brother:{
    name:'Mike',
    fn:function(){
      return this.name
    }
  }
}
console.log(person.brother.fn()); //Mike

上面介绍的都是this的上下文对象调用,下面看一道更高阶的

const o1 = {
  text:'o1',
  fn:function(){
    return this.text
  }
}

const o2 = {
  text:'o2',
  fn:function(){
    return o1.fn()
  }
}
const o3 ={
  text:'o3',
  fn:function(){
    var fn = o1.fn
    return fn()
  }
}
console.log(o1.fn());  //o1
console.log(o2.fn());  //o1
console.log(o3.fn());  //undefined

答案是o1、o1、undefined。

  1. 第一个console最简单,输出o1不难理解,难点在第二个和第三个console上,关键还是看调用this的那个函数。
  2. 第二个console中的o2.fn()最终调用的还是o1.fn(),因此运行结果仍然是o1。
  3. 最后一个console中的o3.fn()通过var fn = o1.fn的赋值进行了‘裸奔’调用,因此这里的this指向window。运行结果就是undefined。

如果再深入一些,想让console.log(o2.fn())语句输出o2。该怎么办? 有两个思路:1. 用call/apply/bind来改变this指向。2. 把o2.fn = o1.fn

console.log(o1.fn.call(o2));
console.log(o1.fn.apply(o2));
console.log(o1.fn.bind(o2)());

如果不使用call/apply/bind应该怎么做? ****** this指向最后调用它的对象 *******

const o1 = {
  text:'o1',
  fn:function(){
    return this.text
  }
}
const o2 = {
  text:'o2',
  fn:o1.fn
}
console.log(o2.fn());

构造函数和this

function Foo(){
  this.user = 'Lucas'
  const o = {}
  return o
}

const foo = new Foo()
console.log(foo.user);  //undefined

function Bar(){
  this.user = 'Lucas'
  const o = {}
  return 1
}
const bar = new Bar()
console.log(bar.user);  //Lucas

这是因为如果构造函数返回一个值,且返回的是一个对象(复杂对象),那么this就指向这个对象。如果返回的不是一个对象(基本类型),那么this仍然指向实例。

箭头函数中的this

var a = 123;
// const a = 123;
const foo = ()=> a=>{
  console.log(this.a);
}
const obj1 = {
  a:2
}
const obj2 = {
  a:3
}

const bar = foo.call(obj1)  //123   const a = 123,则这里打印undefined,原因是const声明的变量不会挂载到window对象上。因此this指向window时,自然就找不到a变量了。
console.log(bar.call(obj2)); //undefined

const a = 123,则这里打印undefined,原因是const声明的变量不会挂载到window对象上。因此this指向window时,自然就找不到a变量了。