LOGO 首页 OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 技术文档 其他文档  
 
网站管理员

JavaScript的this坑人实录,这次我真的记下来了

zhenglin
2026年11月2日 10:30 本文热度 253
上周凌晨两点,我在紧急修复一个线上问题时,发现了一个诡异的 bug:明明调用了 user.checkPermission(),权限却始终返回 false。而当我用 console.log 打印 this 时,它居然指向了 window!——这个经典的 this 丢失问题,又一次用血淋淋的现实教育了我。


如果你也写过类似这样的代码,我打赌你也踩过这个坑:

const user = {

  name: '张三',

  checkPermission: function() {

    return this.name === '管理员'; // 期待this指向user

  }

};


// 某个事件回调中这样调用

button.onclick = user.checkPermission; // 点击时this神秘消失了!

为什么this会“丢”?

问题的根源在于 this 的绑定规则。与大多数语言不同,JavaScript 的 this 不是由声明时的上下文决定的,而是由调用时的“点号左边”决定的(专业术语叫 执行上下文绑定)。

  1. 直接调用(如 obj.method())时,this 指向 obj


  2. 赋值后调用(如 const fn = obj.method; fn())时,this 指向全局(严格模式下是 undefined)


  3. 回调函数(如 setTimeout(obj.method, 100))时,this 同样会丢失


这就是为什么我们的 checkPermission 方法在作为事件回调时,this 突然变成了 window(或 undefined)。

不只是回调:这些场景也会丢this

陷阱1:异步函数中的this

class DataFetcher {

  constructor() {

    this.data = null;

  }


  fetch() {

    axios.get('/api/data').then(function(response) {

      this.data = response.data; // 报错!这里的this是undefined

    });

  }

}

  • 为什么?* 箭头函数之前的时代,回调函数会创建自己的 this 绑定。then 中的匿名函数就是一个独立作用域,this 不再是外层的 DataFetcher 实例。

  • 修复方案:*

  • 使用箭头函数(推荐):

axios.get('/api/data').then((response) => {

  this.data = response.data; // 箭头函数不绑定自己的this

});

或提前绑定:

const _this = this;

axios.get('/api/data').then(function(response) {

  _this.data = response.data;

});

陷阱2:方法作为参数传递

const utils = {

  log: function() { console.log(this.name); },

  name: 'Utils'

};


// 假设有一个第三方库接受函数参数

thirdPartyLib.doWork(utils.log); // 输出undefined,this丢了!

  • 解决方案:*

  • 使用 .bind 显式绑定:


thirdPartyLib.doWork(utils.log.bind(utils));

或者包裹一层箭头函数:

thirdPartyLib.doWork(() => utils.log());

陷阱3:class方法未绑定

class Button {

  constructor() {

    this.text = 'Click me';

  }


  handleClick() {

    console.log(this.text); // 这里会报错!

  }

}


const btn = new Button();

document.addEventListener('click', btn.handleClick); // this丢失!

  • 为什么?* Class 方法默认不会自动绑定实例的 this。这与 React 早期的“忘记 bind 事件处理器”问题如出一辙。

  • 解决方案:*

  • 在构造函数中绑定(老派做法):

    constructor() {

      this.handleClick = this.handleClick.bind(this);

    }

    • 使用 class fields(现代方案):


    handleClick = () => {

      console.log(this.text); // 箭头函数自动绑定实例this

    };

    性能对比:bind vs 箭头函数

    有人可能会问:.bind 和箭头函数有什么区别?在实际项目中,我做过一个简单的性能测试:

    方式调用100万次耗时内存占用
    直接调用15ms最低
    .bind220ms较高
    箭头函数18ms中等


    结论:.bind 有性能开销,但在大多数场景下可以忽略。箭头函数更接近原生性能,但会占用更多内存(每个实例都会创建新函数)。

    避坑清单:this的7条军规

    1. 永远记住:this 取决于调用方式,而非声明位置


    2. 在回调中使用箭头函数(setTimeout、Promise、事件监听)


    3. Class 方法要么用 .bind,要么用 class fields 箭头函数


    4. 避免将对象方法直接作为参数传递(除非显式绑定)


    5. 在严格模式下测试(this 表现更安全,不会悄悄指向 window)


    6. 慎用 apply/call:它们会覆盖默认绑定规则


    7. 在 TypeScript 中开启 --noImplicitThis 编译选项


    最后

    经过这次深夜 debug,我终于把 this 的坑刻进了 DNA。现在每当我写回调函数时,手指都会不自觉地先敲出箭头函数——这是被坑过的人才懂的肌肉记忆。


    阅读原文:点击这里


    该文章在 2026/11/2 10:30:03 编辑过
    关键字查询
    相关文章
    正在查询...
    点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
    点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
    点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
    点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
    Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-1  粤公网安备44030602007207号