解释不同业务场景下 JavaScript 中 this 的值

112 阅读3分钟

大部分 JavaScript 学习者在学习 this 概念时通常觉得一头雾水,许多人觉得是 JavaScript 中最复杂的概念之一,然而 this 值是 JavaScript 面试经典题,搞懂 this 值也是战胜面试的第一步。本篇文章会整理出来 this 值的 5 种判断方式,让读者在面试时能轻易掌握这些概念。

在 JavaScript 中, this 的值是动态的,通常会由被调用的函数来决定。所以,影响 this 的值不是声明的时机,关键在于在哪里被调用。

this 值 5 种判断方式

1. 函数调用

当一个函数不是属于一个对象中的方法时,直接作为函数来调用时, this 会指向全局对象,在浏览器中,默认为 Window 。但有一点要注意的是,如果是在严格模式下, thisundefined

如下代码示例,因为是一般函数调用, this 会是指向 Window,所以第一个输出结果是 Window。而因为在全局范围中用 var 定义 name 变量,因此, name 变量也会绑定到 Window 对象上,第二个输出结果也等同于 window.name 的值。(备注,如果是用 let 定义,并不会绑定在 Window 对象上。)

var name = "John";
function callThis() {
  console.log(this);
  console.log(this.name);
}
callThis();
// Window
// John

2. 对象方法调用

当一个函数是做为一个对象的方法来调用时, this 会指向这个对象。

const john = {
  name: "john",
  callJohn() {
    console.log(`hello, ${this.name}`);
  },
};

john.callJohn(); // hello, john

3. 构造函数调用

当一个函数用 new 关键字调用时,此函数执行前会先创造一个新的对象, this 会指向这个新组成的对象。

如下面代码例子所示,最后调用结果为 Apple 。这是因为当构造函数 Cellphonenew 调用时,会先创造一个新的对象,让 this 会指向这个新对象,=在这个例子中,就打打印出了这个新对象的 brandApple

function Cellphone(brand) {
  this.brand = brand;
}

Cellphone.prototype.getBrand = function () {
  return this.brand;
};

let newIPhone = new Cellphone("Apple");
let newPixelPhone = new Cellphone("Google");

console.log(newIPhone.getBrand()); // Apple
console.log(newPixelPhone.getBrand()); // Google

4. apply、call、bind 方法调用

我们也可以使用 applycallbind 方法来指定 this 指向的对象。

  • apply 方法接受两个参数,第一个是 this 绑定的对象,第二个会放入要传入函数的数组参数,并执行此新函数。
  • call 方法类似为 apply,唯一不同的地方是, apply 第二个参数是数组,但 call 则是依序放在后面。
  • bind 方法通过传入一个对象和要传入的参数,不同于 applycallbind 不会立即执行此心函数,而是会返回此新函数。
function getBrand(prefix) {
  console.log(prefix + this.brand);
}

let apple = {
  brand: "Apple",
};
let sony = {
  brand: "Sony",
};

getBrand.call(apple, "It's a "); // It's a Apple
getBrand.call(sony, "It's an "); // It's an Sony

5. 箭头函数中的 this

ES6 中介绍了一种新的函数类型 - 箭头函数 (arrow function)。但要注意的是,箭头函数并没有属于自己的 this 值,箭头函数的 this 会从他的外在函数继承,若他的外在函数也同为箭头函示,则回继续往上寻找,直到找到全局环境的默认 this 值 (例如:浏览器中就是 window)。

let getThis = () => this;
console.log(getThis() === window); // true