当先锋百科网

首页 1 2 3 4 5 6 7

this到底指向谁

关于this指向的问题,有一种广泛流行的说法就是: 谁调用它,this就指向谁
也就是说,this 的指向是在调用时确定的。这么说没有太大的问题,可是并不全面。事实上,调用函数时会创建属于函数自身的执行上下文。执行上下文的调用创建阶段会确定this的指向,因此我们得出一个结论: this的指向是根据调用函数时的执行上下文所动态确定的

一:全局环境下的this

function fn1(){
	console.log(this)
}
function fn2(){
	'use strict'
	console.log(this)
}
fn1() //window
fn2() //undefined

这种情况是在全局环境下,调用this,非严格模式下指向window对象,严格模式下是undefined。我们再来对全局环境的this进行一下变化考察。

const obj = {
	num:10,
	fn1:function(){
		console.log(this);
		console.log(this.num);
	}
}
let fn2 = obj.fn1;
fn2() //window undefined

这里我们是把obj里的函数fn1赋值给了全局变量下的fn2,调用fn2的时候,就是window对象在进行调用,所以打印this指向了window,打印this.num输出undefined,是因为在全局环境下没有num这个变量,所以输出undefined。就相当于下面代码的调用:

console.log(this) // window
console.log(window.num) // undefined

我们再来进行一下变化考察

const obj = {
	num:10,
	fn1:function(){
		console.log(this);
		console.log(this.num);
	}
}
obj.fn1() 
//{num: 10, fn: ƒ}
//10

上面代码中fn1函数是被obj对象调用,所以会指向obj对象。所以可得:在执行函数时,如果函数是被上一级对象所调用,this就指向上一级对象,否则就指向全局环境

二:上下文对象调用中的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()); // undefine

三:bind/call/apply 改变 this 指向

他们都是用来改变相关函数 this 指向的,但是 call/apply 是直接进行相关函数调用;bind 不会执行相关函数,而是返回一个新的函数,这个新的函数已经自动绑定了新的 this 指向,开发者需要手动调用即可。

const target = {};
fn.call(target, 'arg1', 'arg2');

// 相当于:
const target = {};
fn.apply(target, ['arg1', 'arg2']);

// 相当于:
const target = {};
fn.bind(target, 'arg1', 'arg2')();

四:构造函数和 this

function Foo() {
  this.bar = 'Lucas';
}

const instance = new Foo();
console.log(instance.bar); // Lucas

答案将会输出 Lucas。但是这样的场景往往伴随着下一个问题:new 操作符调用构造函数,具体做了什么? 以下供参考:

  • 创建一个新的对象;
  • 将构造函数的 this 指向这个新对象;
  • 为这个对象添加属性、方法等;
  • 最终返回新对象。

需要指出的是,如果在构造函数中出现了显式 return 的情况,那么需要注意分为两种场景:

function Foo() {
  this.user = 'Lucas';
  const o = {};
  return o;
}
const instance = new Foo();
console.log(instance.user); // undefined

function Foo() {
  this.user = 'Lucas';
  return 1;
}
const instance = new Foo();
console.log(instance.user); // Lucas

结论:如果构造函数中显式返回一个值,且返回的是一个对象,那么 this 就指向这个返回的对象;如果返回的不是一个对象,那么 this 仍然指向实例。

六:箭头函数中的 this 指向

箭头函数使用 this 不适用以上标准规则,而是根据外层(函数或者全局)上下文来决定。

const foo = {
  fn: function () {
    setTimeout(function () {
      console.log(this);
    });
  },
};

foo.fn(); // window

这道题中,this 出现在 setTimeout() 中的匿名函数里,因此 this 指向 window 对象。如果需要 this 指向 foo这个 object 对象,可以巧用箭头函数解决:

const foo = {
  fn: function () {
    setTimeout(() => {
      console.log(this);
    });
  },
};

foo.fn(); // {fn:f}