一篇搞懂this指向

978 阅读3分钟

this是什么

this代表当前执行环境的上下文对象,它是一个代称。

举个例子:比如A班班主任说“这个班的学生是我带过最差的一届”,这里“这个班”指的是A班,因为语境(说话的环境)就是A班。

既然说到了this是根据执行环境来的,那么常见的有哪些环境呢?

this常见场景

1. 作为对象的方法调用,则this指向调用它的对象

let obj={
  a:1,
  fn(){
    console.log(this.a)
  }
}
obj.fn() // obj调用fn(),当前执行环境的上下文对象是obj,所以这里为1

2. 函数直接调用和call,apply

var obj={a:1};
function test(){
  console.log(this)
  function fn(){
    console.log(this)
  }
  fn()
  return fn
}
test() // window window
test.call(obj) // obj window
test().call() //window window window
test().call(obj) //window window obj
var a=1; // window.a = 1
window.b=1;
let b=2 // 存在script作用域里,不会挂在window属性上
let fn2=function(){  // 存在script作用域里,不会挂在window属性上
  console.log(this.a,this.b)
}
function fn(){ // widow.fn = function fn(){}
  console.log(this.a,this.b)
} 

fn() // 1,1
fn2() // 1,1
window.fn() // 1,1
window.fn2() // 报错  window没有fn2方法

解释:

  1. call和apply显示的指定了上下文对象,则函数里this指向这个上下文对象,
  2. 函数直接调用,fn()可以理解为fn.call(),即未指明上下文对象,
  3. fn.call()在非严格模式下,this会指向window,
  4. fn.call()在严格模式下,this指向undefined。

4. 构造函数里的this

this指向new出来的实例,优先级最高,高于bind,call,apply

5. 箭头函数内使用this

箭头函数没有自己的this,执行call,apply,bind无效,作为构造函数使用将报错。

但是只要记住一点,箭头函数里的this在定义时就已经和父级作用域的this绑定了,父级作用域里this指向谁,它就指向谁

node环境

众所周知,node实现了commonjs规范(规范了模块引用、模块定义和模块标识),保证每个js文件就是一个模块,通过require和module.exports实现模块引入和导出。那node的js文件下this有什么特殊性呢?

  1. node环境下的js模块里this指向module.exports,但是如果module.exports指向了一个对象,那this和module.exports指向的就是两个对象了
  2. node环境下globalThis对象指向global,而不是window,所以fn.call()非严格模式下this指向global,严格模式下指向undefined。es6模块默认启用严格模式
console.log(this) // {} 目前 module.exports={}
var a=1
console.log(a) // 1
console.log(this.a) // undefined
exports.a=2 // module.exports.a=2 所以 this.a=2
console.log(this) // {a:2}

module.exports={a:3} // module.exports指向了新对象,和this不是一个对象了
console.log(module.exports) // {a:3}
console.log(this) // {a:2}
function fn(){
  console.log(this)
}
fn() // global对象 相当于fn.call(global)
fn.call(this) // {a:2}

结语

判断this指向法则:

  1. 当前运行环境是是浏览器还是node;
  2. 是否在箭头函数内,如果是参见第四条;
  3. 是否在构造函数内,如果是参见第三条;
  4. 是否是作为方法调用,参见第一条;
  5. 否则看第二条,顺便区分下严格模式即可