JS 中的this

JavaScript 中 this 的绑定主要分为 5 种情况。

核心原则:普通函数的 this 通常由调用方式决定,而不是定义位置。箭头函数除外。

一、默认绑定

普通函数独立调用时,使用默认绑定。

scss 复制代码
function foo() {
  console.log(this);
}

foo();
  • 非严格模式:this 指向 globalThis(浏览器中通常是 window)。
  • 严格模式:this 为 undefined。

二、隐式绑定

函数作为对象的方法调用时,this 指向调用该方法的对象。

javascript 复制代码
const obj = {
  name: "Tom",
  sayHello() {
    console.log(this.name);
  }
};

obj.sayHello(); // Tom

注意,隐式绑定可能丢失:

ini 复制代码
const fn = obj.sayHello;

fn(); // this 不再指向 obj

因为 fn() 是独立调用,不再通过 obj 调用。


① 隐式绑定不仅适用于普通对象,也适用于数组。

② 把对象的方法赋值给变量,会丢失原来的隐式绑定。

js 复制代码
 var length = 1;

    function fun() {
      console.log(this.length);
    }

    let arr = [fun, "a", "b"];

    arr[0](); // 输出什么?3

    let fun2 = arr[0];

    fun2(); // 输出什么?1

补充:函数作为参数传递时的 this 绑定

函数作为参数传递时,只传递函数本身,不会保留原来的隐式绑定。

scss 复制代码
const obj = {
  name: "Tom",
  sayName() {
    console.log(this.name);
  }
};

function execute(fn) {
  fn();
}

execute(obj.sayName); // 默认绑定,不再指向 obj

原因:execute 内部通过 fn() 独立调用函数,而不是通过 obj 调用。

可以通过 bind 保留原来的 this:

scss 复制代码
execute(obj.sayName.bind(obj)); // Tom

核心记忆:判断普通函数的 this,看函数实际如何调用,而不是函数从哪里传过来。

三、显式绑定

通过 call、apply、bind 显式指定 this。

scss 复制代码
function foo() {
  console.log(this.name);
}

const obj = { name: "Tom" };

foo.call(obj);  // Tom
foo.apply(obj); // Tom

const fn = foo.bind(obj);
fn(); // Tom

区别:

方法 是否立即执行 参数传递
call 是 逐个传参
apply 是 数组传参
bind 否 逐个传参,返回新函数

四、new 绑定

通过 new 调用构造函数时,this 指向新创建的实例对象。

ini 复制代码
function Person(name) {
  this.name = name;
}

const p = new Person("Tom");

console.log(p.name); // Tom

结合之前学习的 new 执行过程:

  1. 创建新对象。
  2. 将新对象的原型关联到构造函数的 prototype。
  3. 以新对象作为 this 执行构造函数。
  4. 根据构造函数返回值决定最终返回的对象。

五、箭头函数绑定

箭头函数没有自己的 this,而是继承外层词法环境中的 this。

ini 复制代码
const obj = {
  name: "Tom",

  sayHello() {
    const fn = () => {
      console.log(this.name);
    };

    fn();
  }
};

obj.sayHello(); // Tom

这里:

  • sayHello() 是普通方法,this 指向 obj。
  • fn 是箭头函数,捕获外层 sayHello 的 this。
  • 因此输出 Tom。

箭头函数的 this 无法通过 call、apply、bind 修改。


六、this 绑定的优先级

面试中经常考察多个绑定规则同时存在的情况。

对于普通函数,可以按照下面的优先级判断:

new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定

例如:

ini 复制代码
function Person(name) {
  this.name = name;
}

const obj = { name: "Jack" };

const BoundPerson = Person.bind(obj);

const p = new BoundPerson("Tom");

console.log(p.name);   // Tom
console.log(obj.name); // Jack

即使通过 bind 绑定了 obj,使用 new 时依然会创建新实例,并将 this 指向新实例。

注意:箭头函数不参与上述优先级比较。


七、this 与词法作用域的区别

你刚刚学过词法作用域,这两个概念可以对比理解。

javascript 复制代码
const name = "Global";

const obj = {
  name: "Tom",

  foo() {
    console.log(name);
    console.log(this.name);
  }
};

obj.foo();
// Global
// Tom

这里:

  • name:按照作用域链 查找,找到外层的 name。
  • this.name:先确定 this 指向 obj,再读取 obj.name。

一句话总结:

  • 作用域链:变量在哪里定义,决定去哪里查找。
  • this 绑定 :普通函数怎么调用,决定 this 指向谁。

这是理解 JavaScript 函数执行机制的两个重要维度。

相关推荐
Linux-lucky37 分钟前
45-Linux学习之旅之防火墙与WEB加固
linux·前端·网络·学习·ubuntu
风骏时光牛马3 小时前
生成一个移动端标题,只需要一个标题,不需要其他的任何文本。
前端
IT_陈寒3 小时前
Redis雪崩把我坑惨了,这是5年经验的教训
前端·人工智能·后端
SameX3 小时前
HarmonyOS ArkUI List 的侧滑删除 用 ListItem 的 swipeAction + endIcon 的做法
前端
usdoc文档预览6 小时前
USDOC系列之PPT文件在线编辑-VUE前端实现在线浏览器在线编辑PPT文档
前端·vue.js·编辑器·office365·ppt在线编辑·office文件在线编辑·文件在线编辑
用户2705077725246 小时前
Agent 调工具卡住?3 种超时与取消策略实测对比
前端
LuHang7 小时前
我一行代码没写,把领导派的活做成了公司内部系统😭
前端
明月_清风7 小时前
Meta 开源了一个 AI Native 组件库:Astryx,150+ React 组件,专为 AI Agent 而设计
前端·人工智能·ai编程
用户850869276157 小时前
秒杀系统中 Shell 脚本并发控制 Bug:究竟哪里出了
前端
炫酷的大高个10 小时前
6 亿播放的闪身步,我用前端算出 15 倍重心差
前端·javascript