JavaScript 中的 this 是什么?简介 JavaScript 中为什么存在 this?隐式绑定 显式绑定 new 绑定 词法绑定 窗口绑定 结论

2025-06-10

JavaScript 中的“this”是什么?

介绍

为什么 JavaScript 中存在“this”?

隐式绑定

显式绑定

新的绑定

词汇绑定

窗口绑定

结论

介绍

“this”关键字就是这样一个具有多层次概念的概念,JavaScript 新手常常会觉得它难以理解。

我可以向你保证,读完这篇文章后,你将能够根据函数的执行上下文识别“this”的含义。

在本文中,我们将讨论以下主题:

为什么 JavaScript 中存在“this”?

在深入细节之前,我们先来理解一下 JavaScript 中为什么存在 this。我觉得用一个代码示例来解释会更容易一些:

function sayHello(name) {
    console.log(`Hello ${name}`);
}
Enter fullscreen mode Exit fullscreen mode

上面是“sayHello”函数的声明,它接受“name”作为参数。除非调用该函数并将值传递给“name”参数,否则你无法预知控制台上会显示什么。

sayHello('Skay');

//Output -> Hello Skay
Enter fullscreen mode Exit fullscreen mode

当使用“Skay”调用函数“sayHello”时,控制台上将显示输出“Hello Skay”。

你可以认为 this 关键字的行为与上述函数参数示例非常相似。this 关键字的值会根据函数的调用方式而变化。

简单地说,“this”关键字的存在是为了允许用户在调用函数或方法时决定哪个对象应该是焦点。

隐式绑定

隐式绑定规则指出,为了弄清楚“this”关键字引用什么,首先查看被调用函数的点的左边。

让我们看一个简单的例子来弄清楚上述内容的含义:

const user = {
  name: 'Skay',
  age: 38,
  sayHello: function () {
    console.log(`Hello ${this.name}`); // The 'this' keyword references the 'user' object
  },
};

//Note: Implicit Binding Rule
//To the left of the function call 'sayHello()' the user object is present
//Hence 'this' in this function invocation refers to the 'user' object
console.log(user.sayHello());
//Output -> Hello Skay
Enter fullscreen mode Exit fullscreen mode

注意事项:

  • “用户”对象包含引用“this”关键字的“sayHello”函数。
  • 函数调用“sayHello”函数的左边是用户对象,根据隐式绑定规则,“this”关键字引用“用户”对象。
${this.name} -> gets translated to -> ${user.name}
Enter fullscreen mode Exit fullscreen mode

那么,如果函数调用左边没有任何点,会发生什么呢?这就引出了下一个概念:显式绑定。

显式绑定

让我们以上面的例子为例,将函数“sayHello”移出“用户”对象。

const user = {
  name: 'Skay',
  age: 38,
};

//The function sayHello() moved out of the user object
const sayHello = function () {
  console.log(`Hello ${this.name}`);
};
Enter fullscreen mode Exit fullscreen mode

那么,如何将 user 对象绑定到 sayHello 函数呢?call 函数可以帮我们解决这个问题。

称呼

“call” 是每个函数的属性,传递给“call”的第一个参数将通过显式绑定引用函数内的“this”关键字。

//Using 'call' keyword, we are passing the 'user' object as an argument.
//This explicitly binds the 'user' object to the 'this' keyword
sayHello.call(user);
Enter fullscreen mode Exit fullscreen mode

从上面的代码可以看出,“user”对象使用“call”属性明确绑定到“sayHello”函数。

申请

让我们再举一个接受参数 language1 和 language2 的函数“polyglot”的例子。

const user = {
  name: 'Skay',
  age: 38,
};

const polyglot = function (language1, language2) {
  console.log(
    `Hello, I'm ${this.name} and I know ${language1} and ${language2}`
  );
};
Enter fullscreen mode Exit fullscreen mode

现在,我们知道使用“call”属性,我们可以将用户对象明确绑定到函数并传递参数,如下所示。

polyglot.call(user, 'JavaScript', 'Java');
//Output -> Hello, I'm Skay and I know JavaScript and Java
Enter fullscreen mode Exit fullscreen mode

现在,“apply”关键字使您可以灵活地使用数组而不是单个值来发送多个参数。

//Define the array that needs to be passed as arguments to the function
const languages = ['JavaScript', 'Java'];

//Use the apply keyword to explicitly bind the user object & pass the languages array
polyglot.apply(user, languages);
//Output -> Hello, I'm Skay and I know JavaScript and Java
Enter fullscreen mode Exit fullscreen mode

换句话说,'apply' 与 'bind' 完全相同,只是它为您提供了传递单个数组的灵活性,该数组将把数组的每个元素作为参数传播给函数。

绑定

到目前为止,我们已经了解了显式绑定下的“call”和“apply”关键字。最后一个是“bind”,它与“call”完全相同,但它返回一个函数,该函数可以在稍后调用,而不是立即运行。

让我们看第一个例子并了解“bind”关键字如何与它一起工作。

const user = {
  name: 'Skay',
  age: 38,
};

const sayHello = function () {
  console.log(`Hello ${this.name}`);
};

//The 'bind' keyword returns a function instead of invoking the function immediately
const laterFn = sayHello.bind(user);

//The function is invoked to display the greeting on the console
laterFn(); //Output -> Hello Skay
Enter fullscreen mode Exit fullscreen mode

以上就是关于如何通过显式绑定来识别“this”关键字的各种方法。

新的绑定

在 JavaScript 中,你可以定义一个构造函数,通过它来创建其他对象。让我们看下面的代码示例。

//Fruit is a constructor which accepts name and color as arguments
//Whenever the function 'Fruit' is invoked using the new keyword a new object is created
//The new object created will reference the 'this' keyword
const Fruit = function (name, color) {
  this.name = name;
  this.color = color;
  this.greet = function () {
    console.log(`Hello, I'm ${this.name} and my color is ${this.color}`);
  };
};

//Apple object will be created with the this.name & this.color referencing Apple & Red
const apple = new Fruit('Apple', 'Red');

//Banana Object will be created with the this.name & this.color referencing Banana & Yellow
const banana = new Fruit('Banana', 'Yellow');

//Greet function will be invoked with 'apple' reference
apple.greet(); //Output -> Hello, I'm Apple and my color is Red

//Greet function will be invoked with 'banana' reference
banana.greet(); //Output -> Hello, I'm Banana and my color is Yellow
Enter fullscreen mode Exit fullscreen mode

注意事项:

  • 当使用“new”关键字调用构造函数“Fruit”时,将创建一个新对象。
  • 'this' 关键字在赋值时自然会引用新创建的对象。

词汇绑定

通过代码示例可能更容易解释词汇绑定。

//A Constructor Function that accepts 'name' & 'hobby' array
const Person = function (name, hobbies) {
  this.name = name;
  this.hobbies = hobbies;
  this.display = function () {
        //hobbies array iterated through the map function
    this.hobbies.map(function (hobby) {
            //Inside this anonymous function, the 'this.name' cannot be found
            //Reason -> A new scope gets created within anonymous function
      console.log(`My name is ${this.name} & my hobby is ${hobby}`);
    });
  };
};

const hobbies = ['Sports', 'Music'];

const me = new Person('Skay', hobbies);

me.display();

/** Output
 * My name is  & my hobby is Sports
 * My name is  & my hobby is Music
 */
Enter fullscreen mode Exit fullscreen mode

我们来详细看一下上面的代码示例:

  • “Person” 是一个构造函数,它接受“name”和“hobbies”数组。
  • 我们正在调用名为“Skay”的构造函数以及“爱好”数组“Sports”和“Music”。
  • 当调用“display”函数时,hobbies.map函数也会被调用。
  • hobbies.map 函数中有一个内部匿名函数,它创建了自己的范围,因此当遇到“${this.name}”时,它会尝试在新上下文中搜索“name”,但找不到。
  • 因此输出不会打印“名称”字段。

理想情况下,预期应该在 Person 函数中查找父作用域并找到“name”变量。ES6 箭头函数创建时解决了这个问题。

但是,我们仍然可以通过使用“bind”关键字来解决这个问题,如下面的代码示例所示。

使用 bind

这个例子与上面的例子完全相同,但我们使用了 'bind' 关键字将 'this' 关键字显式绑定到匿名函数。运行该函数,应该会看到 'this.name' 被正确引用,并且输出结果会将名称打印为 'Skay'。

const Person = function (name, hobbies) {
  this.name = name;
  this.hobbies = hobbies;
  this.display = function () {
    this.hobbies.map(
      function (hobby) {
        console.log(`My name is ${this.name} & my hobby is ${hobby}`);
            //By 'explicit' binding the 'this' object the 'this.name' will be referenced
      }.bind(this)
    );
  };
};

const hobbies = ['Sports', 'Music'];

const me = new Person('Skay', hobbies);

me.display();

/** Output
 * My name is Skay & my hobby is Sports
 * My name is Skay & my hobby is Music
 */
Enter fullscreen mode Exit fullscreen mode

ES6 箭头函数

同样的代码可以通过使用箭头函数轻松实现。这是推荐的首选方法,并且兼容所有现代浏览器。

我们只是删除了“function”关键字,并用“arrow”符号替换,使其成为箭头函数。如果您想了解更多信息,这里有一篇关于箭头函数的详细文章。

const Person = function (name, hobbies) {
  this.name = name;
  this.hobbies = hobbies;
  this.display = function () {
    this.hobbies.map((hobby) => {
      console.log(`My name is ${this.name} & my hobby is ${hobby}`);
    });
  };
};

const hobbies = ['Sports', 'Music'];

const me = new Person('Skay', hobbies);

me.display();

/** Output
 * My name is Skay & my hobby is Sports
 * My name is Skay & my hobby is Music
 */
Enter fullscreen mode Exit fullscreen mode

窗口绑定

最后,我们来谈谈窗口绑定,它可能也称为全局上下文。

function displayFruit() {
  console.log(`Hello ${this.fruit}`);
}

displayFruit();

//Output -> Hello Undefined
Enter fullscreen mode Exit fullscreen mode

在上面的代码示例中,没有点运算符,因此没有发生隐式绑定。此外,由于使用了 call、apply、bind 将函数与对象显式绑定,因此 this 关键字被绑定到全局对象,即 window 对象。

如果您将“水果”变量定义为窗口对象并运行上述代码,它将打印水果的名称,如下所示。

function displayFruit() {
  console.log(`Hello ${this.fruit}`);
}

window.fruit = 'Peach';

displayFruit();

//Output -> Hello Peach
Enter fullscreen mode Exit fullscreen mode

严格模式

如果启用了“严格模式”,JavaScript 将不允许 this 关键字的引用默认指向 window 对象。它只会将 this 保留为 undefined,如下面的代码示例所示。

'use strict'

function displayFruit() {
  console.log(`Hello ${this.fruit}`);
}

window.fruit = 'Peach';

displayFruit();

//Output -> Hello undefined
Enter fullscreen mode Exit fullscreen mode

结论

好了,各位!我们已经讲完了如何在 JavaScript 中识别“this”对象的所有内容。

因此,每当您在函数中看到“this”关键字时,您就将应用以下规则:

  1. 检查函数被调用的位置。
  2. 如果点左侧有一个对象,那么该对象就是“this”关键字所引用的对象。如果没有,则继续下一步。
  3. 如果函数是通过“call”、“apply”或“bind”关键字调用的,那么它会明确指出“this”关键字所引用的对象。如果没有,请继续下一步。
  4. 该函数是否使用“new”关键字调用?如果是,则“this”关键字引用的是新创建的对象。如果不是,请继续下一步。
  5. “this” 是否位于箭头函数内部?如果是,则其引用可以在其父作用域中按词法方式找到。如果不是,则继续下一步。
  6. 如果您处于“严格模式”,则“this”关键字未定义。如果不是,请继续下一步。
  7. “this”关键字默认为全局“window”对象。

希望你喜欢这篇文章!欢迎留言评论和反馈。

您可能还对以下内容感兴趣:

鏂囩珷鏉ユ簮锛�https://dev.to/skaytech/what-is-this-in-javascript-3d3i
PREV
3个实用技巧,避免项目半途而废。坦诚地面对自己,了解启动这个项目的动机,并思考这种动机的长期效果。不断评估自己完成工作的能力,例如,你是否知道这需要多少小时,以及你是否在合理地安排自己的节奏。了解自己正在做什么!请帮助我们撰写关于这个主题的下一章。
NEXT
Git Hooks 是什么?简介 Git Hooks 是什么?为什么要使用 Git Hooks?如何实现 Hook?实例 Git 预推送 Hook?如何绕过 Hook?版本控制 - Git Hooks 总结