【无标题】

JavaScript 中的 this 指向:四种绑定规则与优先级详解

this 是 JavaScript 中一个核心且容易混淆的概念。它的指向不是在定义时确定的,而是在调用时确定的 (即在执行上下文创建时绑定)。本文将系统梳理 this 的四种绑定规则、优先级以及箭头函数的特殊行为。

一、四种绑定规则

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

当函数以独立函数形式调用(不作为对象的方法,也不通过 call/apply/bindnew 调用)时,this 默认绑定到全局对象。

  • 浏览器环境:window
  • Node.js 环境:global
  • 严格模式('use strict'):undefined
javascript 复制代码
function foo() {
  console.log(this); // 非严格模式: window; 严格模式: undefined
}
foo();

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

当函数作为某个对象的方法被调用时,this 隐式绑定到该调用对象。如果有多层对象嵌套,this 指向最近一层的调用对象。

javascript 复制代码
const obj = {
  name: 'Alice',
  greet() {
    console.log(this.name);
  }
};
obj.greet(); // 'Alice'

const outer = {
  inner: {
    name: 'Bob',
    greet() {
      console.log(this.name);
    }
  }
};
outer.inner.greet(); // 'Bob'(this 指向 inner,而非 outer)

3. 显式绑定(主动指定)

通过 callapplybind 方法可以主动指定函数的 this 指向,这是最灵活的绑定方式。

call / apply / bind 的区别
方法 是否立即执行 参数传递方式
call 第一个参数是 this 指向,后续参数逐个列举
apply 第一个参数是 this 指向,第二个参数为数组
bind 否(返回新函数) 预设 this 和部分参数,返回的新函数永久绑定(硬绑定)
javascript 复制代码
function say(age) {
  console.log(`${this.name}, ${age}`);
}
const person = { name: 'Tom' };

say.call(person, 25);      // Tom, 25
say.apply(person, [25]);   // Tom, 25
const bound = say.bind(person, 25);
bound();                   // Tom, 25

4. new 绑定(构造函数调用)

当函数通过 new 关键字调用时,作为构造函数,this 绑定到新创建的实例对象。

new 操作符内部执行四个步骤:

  1. 创建一个空的新对象。
  2. 将该新对象的 __proto__ 指向构造函数的 prototype
  3. 将构造函数的 this 绑定到这个新对象。
  4. 如果构造函数没有返回对象,则返回这个新对象;如果返回了一个对象,则返回该对象(此时 this 绑定失败,返回的是手动返回的对象)。
javascript 复制代码
function Person(name) {
  this.name = name;
}
const p = new Person('John');
console.log(p.name); // 'John'

二、优先级:多个规则同时生效时,谁为准?

this 绑定的优先级从高到低为:

new 绑定 > 显式绑定(特别是 bind) > 隐式绑定 > 默认绑定

javascript 复制代码
function foo() { console.log(this.name); }
const obj1 = { name: 'obj1', foo };
const obj2 = { name: 'obj2', foo };

obj1.foo();                // 'obj1'(隐式绑定)
obj1.foo.call(obj2);       // 'obj2'(显式绑定 > 隐式绑定)

const bound = foo.bind(obj1);
bound.call(obj2);          // 'obj1'(bind 硬绑定后无法再被 call/apply 改变)

const instance = new bound(); // 如果 foo 不是构造函数则报错,但若可作为构造函数,new 优先级高于 bind(新对象会覆盖 bind 绑定的 this)

注意bind 生成的硬绑定函数,其 this 不会被 call/apply 覆盖,但 new 操作可以覆盖 bind 的绑定(因为 new 优先级最高)。

三、箭头函数:没有自己的 this 绑定规则

箭头函数不绑定自己的 this ,它的 this 继承自定义时外层词法作用域 (即箭头函数声明时所在上下文的 this),并且无法通过 callapplybind 修改。

javascript 复制代码
const obj = {
  name: 'Eve',
  greet: () => {
    console.log(this.name); // 此处的 this 是外层(全局或上层函数)的 this,不是 obj
  }
};
obj.greet(); // undefined(假设全局没有 name)

箭头函数与普通函数的核心区别

特性 普通函数 箭头函数
this 绑定 调用时动态绑定(四种规则) 定义时继承外层 this,不可变
构造函数能力 可以(new 调用) 不能(new 会报错)
prototype 属性
arguments 对象 有(类数组) 无(可用剩余参数 ...args
简写语法 function() {} () => {},单参数可省略括号

特别注意

定义对象时的大括号 {} 不是一个单独的执行环境 ,它依旧处于全局环境中。因此对象字面量内部的方法若使用箭头函数,其 this 仍指向外层作用域(通常是 window 或模块作用域),而不是该对象。

javascript 复制代码
const obj = {
  name: 'Test',
  arrow: () => console.log(this.name),
  normal() { console.log(this.name); }
};
obj.arrow();  // undefined(this 指向全局)
obj.normal(); // 'Test'

四、总结速查表

调用方式 this 指向
普通函数独立调用 非严格模式:全局对象;严格模式:undefined
对象方法调用 该对象(最近一层)
call/apply/bind 显式指定的对象(bind 返回的函数不可再改变)
new 构造函数调用 新创建的实例对象
箭头函数 定义时外层作用域的 this(不可改变)

理解 this 的关键在于记住:不看定义在哪,只看如何调用

相关推荐
YikNjy24 分钟前
break和continue
java·开发语言·算法
秋942 分钟前
java项目中cpu飙升排查及解决方法
java·开发语言
野生技术架构师42 分钟前
牛客网2026最新大厂Java高频面试题精选(附标准答案)
java·开发语言
PH = 71 小时前
JAVA的SPI机制
java·开发语言
IT猿手1 小时前
多目标优化算法:多目标蛇优化算法(Multiple Objective Snake Optimizer,MOSO)(提供MATLAB代码)
开发语言·算法·matlab·动态路径规划·光伏模型参数估计
朔北之忘 Clancy1 小时前
2026 年 3 月青少年软编等考 C/C++ 一级真题解析
c语言·开发语言·c++·青少年编程·题解·考级
不好听6131 小时前
JavaScript 到底是怎么运行的?从编译阶段到执行上下文全面解析
javascript
小成202303202651 小时前
C++~01面向对象基础
开发语言·c++
会编程的土豆1 小时前
Go 方法接收者超清晰笔记(类型名 vs 变量名)
开发语言·笔记·golang
丷丩1 小时前
MapLibre GL JS第29课:添加Canvas源
javascript·gis·map·mapbox·maplibre gl js