this到底是什么?

668 阅读3分钟

前言

this是JavaScript世界最让人迷惑的关键字之一,如果不明白this的本质,基本上会被一线互联网公司的面试官扣大量的分。上下文问有提到过this是上下文中确定的那么我们来了解下什么是this。

为什么要有this?

function func() {
  console.log(aaa);
}

如上述代码,函数func打印变量aaa,问题是这个函数func可以在任意其他执行上下文中被调用,因此这个a可能就指向不同了。

this就是指向当前代码运行时所处的上下文环境

this的一些理解

this 既不指向函数自身也不指向函数的作用域

  • this的指向,是在函数被调用的时候确定的,也就是执行上下文被创建时确定的。
  • this 的指向和函数声明的位置没有任何关系,只取决于函数的调用位置(也即由谁、在什么地方调用这个函数) 。
  • 正因为在执行上下文的创建阶段this的指向就已经被确定了,在执行阶段this指向不可再被更改。

this指向规则

默认指向

默认this是指向全局对象window的

function func() {
    console.log( this.b ); // this指向全局对象
}
var b = 3;
func(); // 3
  • 这是在默认正常执行环境下会执行window
  • 如果开启了严格模式,那么func()将会变为undefined,this执行undefiend
function func() {
  "use strict";//函数体处于严格模式下,this指向undefined
  console.log(this.age);
}

var age = "22";
(function() {
  func(); //age of undefined
})();

setTimeout和setInterval指向?

可以发现在setInterval和setTimeout中传入函数时,函数中的this会指向window对象

var num = 0;
class Obj {
    constructor(num){
        this.num = num;
    }
    func(){
        console.log(this.num);
    }
    func1(){
        setTimeout(function () {
            console.log("setTimeout:"+this.num);
        }, 1000)
    }
    func2(){
        setInterval(function () {
            console.log(this.num);
        }, 2000)
    }
}
var obj = new Obj(1);
obj.func();//>> 1              输出的是obj.num
obj.func1()//>> setTimeout:0   输出的是window.num
obj.func2()//>> 0 0 0 0 ……     输出的是window.num

可能是匿名函数做的鬼>v<,当然可以使用bind进行修正this指向即可解决

隐式this

通过执行时的上下文来决定,也就是调用的位置。

function func() {
    console.log(this.a);
  }
  var obj = {
    a: 2,
    func: func
  };
  obj.func(); // 2
  • 找到调用位置,由 obj 对象来调用函数func,
  • 此时可以说函数func被调用时,obj 对象“拥有”或者“包含”func函数,
  • 所以此时的 this 指向调用 func 函数的 obj 对象。

隐式丢失?

function func() {
    console.log( this.a );
}

var obj = {
    a: "coffe1891",
    func: func
};

var bar = obj.func; // 间接引用,见本文【壹.2.3.6】。此时bar和obj.func其实
                    // 都指向内存中的函数func本身。
var a = "oops, global"; // a 是全局对象window的属性,也是全局变量
bar(); //>> oops, global
  • 可以理解为 bar 是 obj.func 的一个引用,但是实际上,它引用的是func函数本身
  • bar() 其实是一个不带任何定语的独立函数调用,所以就按默认指向,执行window

显式this

JavaScript内置对象Function的三个原型方法call()、apply()和bind(),它们的第一个参数是一个对象,它们会把这个对象绑定到this,接着在调用函数时让this指向这个对象。

var a = "makai";

function func() {
    console.log( this.a );
}
var obj = {
    a:"123123"
};

func.call(obj); // 123123
// 在调用 func 时强制把它的 this 绑定到 obj 上

bind和call就不用我多说了把 bind不会立即执行,而apply会立即执行和call一样,区别在于传参不同

new中的this

通过 new的方式,this永远指向新创建的对象

function func(name) {
    this.name = name;
    this.getName = function() {
      return this.name;
    };
  }
  
  var obj = new func("biubiubiu"); //this会指向obj
  obj.getName()//biubiubiu

箭头函数的this

箭头函数的自身是没有this的,箭头函数的 this与声明所在的上下文相同, 默认为window,严格模式为undefined

var b = 11
var obj = {
    b: 22,
    a: () => {
        console.log(this.b);
    }
}
// 对象调用箭头函数
obj.a(); // 11  thi=>window

over 快乐每一天

本文使用 mdnice 排版