广州总部电话:020-85564311
广州总部电话:020-85564311
20年
互联网应用服务商
请输入搜索关键词
知识库 知识库

优网知识库

探索行业前沿,共享知识宝库

理解 Javascript 的 this

发布日期:2025-08-20 18:29:20 浏览次数: 807 来源:青竹梦呓
推荐语
深入解析JavaScript中this的动态绑定机制,掌握6种绑定规则,彻底告别this困惑。

核心内容:
1. JavaScript内存模型与执行上下文的关系
2. this的动态绑定原理与执行上下文的关系
3. this的6种绑定规则及实际应用场景
小优 网站建设顾问
专业来源于二十年的积累,用心让我们做到更好!

0x01、内存模型

JavaScript 内存分为两部分:

  • 栈(Stack):存储原始类型和执行上下文
  • 堆(Heap):存储引用类型(对象、函数、数组)

示例:

let age = 30;                 // 原始类型 → 栈
const user = { name"Alice" }; // 对象 → 堆

内存示意:

栈 (Stack)                 | 堆 (Heap)
---------------------------|----------------------------
全局执行上下文               |
- age: 30                  |
- user: <地址 0x01>         |
---------------------------|----------------------------
                           | 地址 0x01: { name: "Alice" }

0x02、执行上下文

在 JavaScript 中,this 不是静态的,而是动态绑定的。它的值在函数调用时确定,而不是在定义时。

理解 this 的关键在于理解 执行上下文(Execution Context)

每个函数被调用时,都会创建一个新的执行上下文,其中包含:

  • Lexical Environment(词法环境,存储变量和函数)
  • Variable Environment(用于 var 声明)
  • this 绑定(当前上下文的核心属性)

内存结构示意:

栈 (Stack)                 | 堆 (Heap)
---------------------------|----------------------------
函数执行上下文               |
- LexicalEnv: { ... }      |
- this: <指向的对象>        |
-------------------------- |----------------------------
                           | 对象/函数存储在堆中

0x03、this 的 6 种绑定规则

1. 默认绑定(独立函数调用)

在独立函数调用中,this 的绑定规则是,在浏览器非严格模式下指向window对象,严格模式下是 undefined,如:

function show({
  console.log(this);
}
show(); // window 或者 undefined

[!info] ES5 引入的严格模式下,默认绑定不再指向全局对象,而是 undefined
ES2020 之后,推荐使用 globalThis 来访问全局对象,它在浏览器、Node.js 等环境下统一。

内存示意:

栈 (Stack)                   | 堆 (Heap)
-----------------------------|----------------------------
show() 执行上下文              |
- this: <全局对象 或 undefined>|
-----------------------------|----------------------------
全局执行上下文                 |
- show: <函数>                |
-----------------------------|----------------------------
                             | 全局对象(window / globalThis)

2. 隐式绑定(方法调用)

在方法调用中,this 指向调用的对象,如:

const user = {
  name"Bob",
  greet() {
    console.log(`Hello, ${this.name}!`);
  }
};
user.greet(); // "Hello, Bob!"

内存示意:

栈 (Stack)              | 堆 (Heap)
------------------------|----------------------------
greet() 执行上下文        |
- this: <地址 0x01>      |
------------------------|----------------------------
全局执行上下文            |
- user: <地址 0x01>      |
------------------------|----------------------------
                        | 地址 0x01: {
                        |   name: "Bob",
                        |   greet: <函数>
                        | }

3. 显式绑定(call/apply/bind)

显式绑定的时候,this 指向显式绑定的对象,如:

function greet({
  console.log(`Hello, ${this.name}!`);
}
const alice = { name"Alice" };
greet.call(alice); // "Hello, Alice!"

内存示意:

栈 (Stack)                 | 堆 (Heap)
---------------------------|----------------------------
greet() 执行上下文          |
- this: <地址 0x02>        |
---------------------------|----------------------------
全局执行上下文               |
- alice: <地址 0x02>       |
---------------------------|----------------------------
                           | 地址 0x02: { name: "Alice" }

4. new 绑定(构造函数)

通过 new 创建对象的时候,this 指向新创建的对象,如:

function User(name{
  this.name = name;
}
const bob = new User("Bob");
console.log(bob.name); // "Bob"

内存示意:

栈 (Stack)                 | 堆 (Heap)
---------------------------|----------------------------
User() 执行上下文           |
- this: <地址 0x03>        |
---------------------------|----------------------------
全局执行上下文               |
- bob: <地址 0x03>         |
---------------------------|----------------------------
                           | 地址 0x03: { name: "Bob" }

5. 箭头函数(词法绑定)

当使用箭头函数的时候,this 指向外层词法作用域的 this,如:

const counter = {
  count0,
  increment() {
    setTimeout(() => {
      this.count++; // this 继承自 increment
    }, 100);
  }
};
counter.increment(); // 隐式绑定

内存示意:

栈 (Stack)                 | 堆 (Heap)
---------------------------|----------------------------
increment() 执行上下文      |
- this: <地址 0x04>        |
---------------------------|----------------------------
setTimeout 回调(箭头函数)  |
- [[This]]: <地址 0x04>    |
---------------------------|----------------------------
全局执行上下文               |
- counter: <地址 0x04>     |
---------------------------|----------------------------
                           | 地址 0x04: {
                           |   count: 1,
                           |   increment: <函数>
                           | }

6. class 中的 this

情况一:普通方法

普通方法的方法定义在原型上:

class User {
  name = "Alice";
  greet() {
    console.log(`Hello, ${this.name}`);
  }
}

const u = new User();
u.greet(); // Hello, Alice

const fn = u.greet;
fn(); // TypeError: Cannot read properties of undefined

内存示意:

栈 (Stack)                 | 堆 (Heap)
---------------------------|----------------------------
fn() 执行上下文             |
- this: undefined          |
---------------------------|----------------------------
全局执行上下文               |
- u: <地址 0x01>           |
- fn: <地址 0x02>          |
---------------------------|----------------------------
                           | 地址 0x01: { name: "Alice" }
                           | User.prototype: { greet: <地址 0x02> }
                           | 地址 0x02: function greet() { ... }

情况二:箭头函数

箭头函数的方法定义为实例属性:

class User {
  name = "Alice";
  greet = () => { console.log(`Hello, ${this.name}`); }
}
const u = new User();
const fn = u.greet;
fn(); // "Hello, Alice"

内存示意:

栈 (Stack)                 | 堆 (Heap)
---------------------------|----------------------------
fn() 执行上下文             |
- this: <继承自外层作用域>   |
---------------------------|----------------------------
全局执行上下文               |
- u: <地址 0x03>           |
- fn: <地址 0x04>          |
---------------------------|----------------------------
                           | 地址 0x03: {
                           |   name: "Alice",
                           |   greet: <地址 0x04>
                           | }
                           | 地址 0x04: () => { ... }
                           |   [[This]]: 固定为 <地址 0x03>

0x04、this 与闭包的内存关系

闭包让函数能访问外层作用域的变量,但要注意箭头函数继承的 this 并不会自动绑定到返回对象。

错误示例:

function createCounter({
  let count = 0;
  return {
    increment() => { count++; this.log(); },
    log() => console.log(count)
  };
}

正确写法:

function createCounter({
  let count = 0;
  return {
    increment() { count++; this.log(); },
    log() { console.log(count); }
  };
}

0x05、常见问题与解决方案

问题 1:回调函数丢失 this

const user = {
  name"Alice",
  greet() {
    setTimeout(function({
      console.log(this.name); // undefined
    }, 100);
  }
};

解决方案:使用箭头函数

setTimeout(() => {
  console.log(this.name); // "Alice"
}, 100);

问题 2:方法赋值丢失 this

const user = { name"Alice", greet() { console.log(this.name); } };
const greet = user.greet;
greet(); // undefined

解决方案:bind

const boundGreet = user.greet.bind(user);
boundGreet(); // "Alice"

问题 3:嵌套函数丢失 this

const obj = {
  value42,
  getValue() {
    function helper({
      return this.value; // undefined
    }
    return helper();
  }
};

解决方案:箭头函数或变量保存

// 箭头函数
const helper = () => this.value;

// 变量保存
const self = this;
function helper({
  return self.value;
}

问题 4:模块中的 this

在 ES6 模块中,顶层 this === undefined,而不是全局对象。

// module.js
console.log(this); // undefined

问题 5:事件监听中的 this

button.addEventListener("click"function({
  console.log(this); // button 元素
});

button.addEventListener("click", () => {
  console.log(this); // 外层作用域(比如 window 或 class 实例)
});

优网科技,优秀企业首选的互联网供应服务商

优网科技秉承"专业团队、品质服务" 的经营理念,诚信务实的服务了近万家客户,成为众多世界500强、集团和上市公司的长期合作伙伴!

优网科技成立于2001年,擅长网站建设、网站与各类业务系统深度整合,致力于提供完善的企业互联网解决方案。优网科技提供PC端网站建设(品牌展示型、官方门户型、营销商务型、电子商务型、信息门户型、微信小程序定制开发、移动端应用(手机站APP开发)、微信定制开发(微信官网、微信商城、企业微信)等一系列互联网应用服务。


我要投稿

姓名

文章链接

提交即表示你已阅读并同意《个人信息保护声明》

专属顾问 专属顾问
扫码咨询您的优网专属顾问!
专属顾问
马上咨询
联系专属顾问
联系专属顾问
联系专属顾问
扫一扫马上咨询
扫一扫马上咨询

扫一扫马上咨询

和我们在线交谈!