this浅谈

332 阅读3分钟

this是使用JavaScript开发过程中,一个很常见的基础知识点,但同时也是一个很容易出现混淆的点。作为这样一个高频、且基础的知识点,做一次总结,就显得尤为重要。

与其他语言索引,函数的this关键字在JavaScript中的表现略有不同,变量,在严格模式和非严格模式之间也会有一些区别。在绝大多数情况下,函数的调用方式决定了this的值(运行时绑定)。this不能在执行期间被赋值,并且在每次函数被调用时this的值也可能会不同。ES5引入了bind方法来设置函数的this值,而不用考虑函数如何被调用的。ES2015了引入箭头函数,箭头函数不提供自身的this绑定(this的值将保持为闭合词法上下文的值)。

这是MDN对于this的简单介绍。从这个介绍中,我们可以总结出关于this的几个重点。

  1. 严格模式与非严格模式,this的指向是有区别的;
  2. this是在函数运行时才绑定;
  3. 我们可以通过一些方法来设置函数的this值;
  4. 箭头函数不提供自身的this绑定。 下面我们来通过一些例子,了解下this的这些关键特性

全局上下文

无论严格模式还是非严格模式,在全局执行环境中this都是指向全局对象的。这个全局对象在浏览器中,通常是window;在Node环境中,则是globalThis

a = 37;
console.log(this.a) //37

函数上下文

在函数里,this的值取决于调用方式。且严格模式与非严格模式有所区别。

function f1() {
  return this;
}
//非严格模式
f1() === window; //true
function f1() {
  "use strict";
  return this;
}
//严格模式
f1() === undefined; //true

绑定this的方法

ECMA5引入Function.prototype.bind()Function.prototype.call()Function.prototype.apply()他们都是完成对this的绑定。

  • bind()
function f(){
  return this.a;
}

var g = f.bind({a:"xiaobai"});
console.log(g()); // xiaobai

var h = g.bind({a:'xiaohei'});
console.log(h()); // xiaobai

bind()将this永久绑定至它的第一个参数上。

  • apply()
var a = {
    user:"xiaobai",
    fn:function(e,ee){
        console.log(this.user);
        console.log(e+ee);
    }
}
var b = a.fn;
var arr = [500,20];
b.apply(a,arr);//xiaobai 520

apply()可以将this的绑定到第一个参数上,同时可以接收多个参数,作为实参传进去,但它的参数只能为数组。

  • call()
var a = {
    user:"xiaobai",
    fn:function(e,ee){
        console.log(this.user);
        console.log(e+ee);
    }
}
var b = a.fn;
b.call(a,1,2); //xiaobai 3

call()可以将this的绑定到第一个参数上,同时可以接收多个参数,作为实参传进去。

箭头函数

在箭头函数中,this与封闭词法环境的this保持一致。在全局代码中,它将被设置为全局对象。

var obj = {
  bar: function() {
    var x = (() => this);
    return x;
  }
};

var fn = obj.bar();
console.log(fn() === obj); // true

var fn2 = obj.bar;
console.log(fn2()() === window); // true

当我们调用obj时,此时this绑定了它外部的词法作用域,也就是也obj上,所以fn() === obj; 当直接引用obj时,此时的this则是绑定了仍是它外部的词法作用域,但这时变成了window,所以fn2()() === window.

关于new

前面已经将this的一些基本用法介绍完了,但仍存在一个特性,就是在构造函数中,使用new关键字生成实例时,此时的this时如何绑定的呢?

function Fn1(){
  this.a = 37;
}

var o = new Fn1();
console.log(o.a); // 37


function Fn2(){
  this.a = 37;
  return {a:38};
}

o = new Fn2();
console.log(o.a); // 38

当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。但如果函数具有返回对象的return语句,则该对象将是 new 表达式的结果。否则,表达式的结果是当前绑定到 this 的对象。

结语

至此,关于this的基本用法也就介绍完毕了,总结一句话:this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用,但其中的也有一些特殊情况,需要我们格外注意。如文章内有错误,欢迎指正。