我把对象的方法当回调传给了 setTimeout,结果一执行就报 this 是 undefined、方法里的属性全访问不到,我对着这个丢了 this 的方法排查了大半天的复盘

我的方法在 obj 上直接调用一切正常,可一把它当回调传给 setTimeout(或事件监听、forEach),回调一执行就报 Cannot read properties of undefined——打印 this 竟是 undefined,方法里 this.xxx 全访问不到。同一个方法,直接调好好的,怎么一传出去 this 就丢了?深挖才懂:JavaScript 的 this 不是定义时绑定,而是"调用时决定"的,取决于"函数怎么被调用"——具体说就是"点号前面是谁"。obj.method() 是通过 obj. 调用,this 指向 obj;而 setTimeout(obj.method) 只把函数本身拆出来传过去、和 obj 脱了钩,将来被光秃秃地调用,this 就成了 undefined。这篇从 this 的四条绑定规则(默认/隐式/显式/new)+ 箭头函数词法 this 讲起,到箭头函数包裹/bind/箭头函数类字段锁住 this 的正解、箭头函数何时是解药何时是毒药、this 丢失的高频场景速查,以及那句最戳心的——最危险的不是你不知道的知识,而是你以为自己知道、其实理解错了的,对"似曾相识"要保持最高警惕。

我把对象的方法当回调传给了 setTimeout,结果一执行就报 this 是 undefined、方法里的属性全访问不到,我对着这个丢了 this 的方法排查了大半天的复盘

这是一个让我对 JavaScript 的 this 彻底改观的故事。我写了一个类(或对象),里面有个方法,方法里要用 this 去访问对象自己的属性。我在对象上直接调用它时,一切正常。可当我把这个方法,作为回调,传给 setTimeout(或事件监听、数组的 forEach)时,诡异的事发生了:回调一执行,就报错:Cannot read properties of undefined(无法读取 undefined 的属性);我打印 this 一看,它竟然变成了 undefined(或者在非严格模式下变成了 window/全局对象)——总之,this 不再指向我那个对象了,方法里所有 this.xxx 自然全都访问不到。

我当时一脸懵:明明是同一个方法,我直接调用它就好好的,怎么一传给 setTimeout,this 就"丢"了?方法还是那个方法,它的 this 怎么会变?我顺着这个现象深挖,才终于揭开真相,补上了我对 JavaScript 一个最核心、也最反直觉的认知漏洞:问题的核心,在于 JavaScript 里 this绑定规则,和绝大多数语言都不一样。我一直想当然地以为,一个方法的 this,是在定义时"绑死"在它所属的那个对象上的(就像很多语言那样);可真相是:JavaScript 里,this 的指向,不是在"定义时"决定的,而是在"调用时"才决定的;而且,它取决于"这个函数是怎么被调用的"——具体说,是". 点号前面是谁"当我写 obj.method() 时,是通过 obj. 调用的,所以 this 指向 obj,一切正常;可当我写 setTimeout(obj.method) 时,我只是把 method 这个函数本身取了出来、传了过去,它和 obj联系,在这一刻就被切断了;等到 setTimeout 在未来调用它时,是"光秃秃地"调用(前面没有任何对象),于是 this不再指向 obj,而是变成了 undefined(严格模式)或全局对象。我这才痛彻地明白:在 JavaScript 里,方法和它的 this,是"可以分离"的——方法只是一个恰好挂在对象上的、独立的函数;this 是谁,不看这个函数"属于"谁,而看它"被谁调用"。这个"this 在调用时动态决定"的特性,是 JS 最大的"坑王"之一;一旦你把一个方法"拆下来"、脱离了它的对象去传递和调用,它的 this,就极有可能""。要驾驭 JavaScript,彻底搞懂 this 的四条绑定规则,是一道绕不开的坎。

故障现场:方法被"拆下来"传递,this 在调用时丢失

我把这个"this 丢失"的现场,用代码摊开给你看:

// ✗ 灾难: 把方法"拆下来"当回调, this 在调用时丢失
class Timer {
  constructor() {
    this.seconds = 0;
  }
  tick() {
    this.seconds++;            // ✗ 依赖 this 指向 Timer 实例
    console.log(this.seconds);
  }
}

const timer = new Timer();
timer.tick();                  // ✓ 正常: 通过 timer. 调用, this = timer

// ✗ 把方法"拆下来"传给 setTimeout
setTimeout(timer.tick, 1000);  // ✗ 1秒后报错: Cannot read properties of undefined
//   等价于:
//   const fn = timer.tick;     // 只取出函数本身, 和 timer 脱钩了!
//   fn();                      // "光秃秃"调用, 前面没有对象 → this = undefined

// 同样的坑:
button.addEventListener("click", timer.tick);   // ✗ this 指向 button, 不是 timer
arr.forEach(timer.tick);                         // ✗ this 丢失
const { tick } = timer; tick();                  // ✗ 解构出来再调, this 丢失

// 为什么 this 会丢?
//   - JS 的 this 不是"定义时绑定", 而是"调用时决定"。
//   - 看"怎么调用": obj.fn() → this=obj; 而"光秃秃" fn() → this=undefined(严格)。
//   - setTimeout(timer.tick) 只传了函数本身, 切断了和 timer 的联系。
//   - 将来 setTimeout 内部"光秃秃地"调用它 → this 不再是 timer。

// 口诀: this 看"调用时点号前面是谁", 没有点号前缀就丢了。

// 根因: JS 的 this 在调用时动态决定; 方法被拆下来脱离对象调用时, this 丢失。

看着这段代码,我才算彻底想明白了这场"this 丢失"的根源。问题的核心,是 JavaScript 里 this"调用时决定",不是"定义时绑定"timer.tick() 为什么正常?因为它是通过 timer. 调用的,"点号前面是 timer",所以 this 指向 timersetTimeout(timer.tick, 1000) 为什么崩?因为它只把 tick 这个函数本身取出来传了过去(等价于 const fn = timer.tick; fn();),timer 脱钩了;将来 setTimeout 内部"光秃秃地"调用它(前面没有任何对象),this变成了 undefined(严格模式)或全局对象同样的坑,出现在 addEventListener(timer.tick)(this 指向 button)、arr.forEach(timer.tick)、以及解构 const {tick} = timer; tick()——只要你把方法"拆下来"、脱离了它的对象去调用,this 就丢。我总结了一句口诀:this 看"调用时点号前面是谁",没有点号前缀就丢了归根结底:JS 的 this 在调用时动态决定;方法被拆下来、脱离对象调用时,this 就丢失——这,就是根源。

第一件事:搞懂 this 的四条绑定规则

定位到根源,我必须把 JavaScript 里 this 的绑定规则,从根上彻底搞清楚:

JS 的 this: 调用时决定, 取决于"函数怎么被调用"

# 核心: this 不是定义时绑定, 是"调用时"根据"调用方式"决定的。
#   一个函数的 this 是谁, 看它"怎么被调用", 而不是它"定义在哪/属于谁"。

# 四条绑定规则(优先级从低到高):
# 1. 默认绑定: 光秃秃地调用 fn()
#    → this = undefined(严格模式) / 全局对象(非严格)。
#    例: const f = obj.m; f();  → this 丢失!(本文的坑)

# 2. 隐式绑定: 通过对象调用 obj.fn()
#    → this = 点号前面那个对象 obj。
#    例: timer.tick()  → this = timer。
#    ⚠ 隐式绑定"易丢失": 把 obj.fn 赋值/传参后再调, 就退化成默认绑定。

# 3. 显式绑定: call / apply / bind 手动指定
#    → this = 你传进去的那个。
#    例: fn.call(timer) / fn.bind(timer)  → this = timer。

# 4. new 绑定: new Fn()
#    → this = 新创建的那个实例对象。

# 箭头函数: 没有自己的 this!
#    - 箭头函数不遵循上面四条, 它的 this "继承"自定义时的外层作用域(词法 this)。
#    - 一旦定义, this 就固定了, 不随调用方式改变 → 正好用来"锁住" this。

# 判断 this 的步骤(从上往下看哪条匹配):
#   是 new 调用吗? → 实例
#   是 call/apply/bind 吗? → 指定的
#   是 obj.fn() 吗? → obj
#   都不是(光秃秃 fn())→ undefined/全局
#   是箭头函数吗? → 看外层词法作用域(不参与上面判断)

# 核心: this 由调用方式决定(默认/隐式/显式/new 四规则), 隐式绑定易丢失;
#   箭头函数没有自己的 this, 继承外层, 可用来锁定 this。

原理终于清晰了。JavaScript 里 this核心规则是:它不是定义时绑定,而是"调用时"根据"调用方式"决定的——一个函数的 this 是谁,看它"怎么被调用",而不是它"定义在哪、属于谁"具体有四条绑定规则:第一,默认绑定——光秃秃地 fn(),thisundefined(严格)或全局对象(这正是本文的坑);第二,隐式绑定——通过对象 obj.fn(),this点号前面那个对象(但它"易丢失":obj.fn 赋值/传参后再调,就退化成默认绑定);第三,显式绑定——call/apply/bind 手动指定;第四,new 绑定——new Fn(),this 是新实例。箭头函数是个特殊存在:没有自己的 this!它不遵循上面四条,而是"继承"自定义时的外层作用域(词法 this);一旦定义,this 就固定了、不随调用方式改变——这恰好可以用来"锁住" this判断 this 的步骤,就是从上往下看哪条匹配:是 new 吗→实例;是 call/apply/bind 吗→指定的;是 obj.fn() 吗→obj;都不是(光秃秃)→undefined/全局;是箭头函数吗→看外层词法作用域归根结底:this 由调用方式决定(默认/隐式/显式/new 四规则),隐式绑定易丢失;箭头函数没有自己的 this、继承外层,可用来锁定 this

第二件事:正解——用箭头函数或 bind 锁住 this

搞懂了原理,正解就清晰了:既然 this 在"光秃秃调用"时会丢,那就主动把它"锁死"在我们想要的对象上——用箭头函数bind

// ✓ 正解一: 用箭头函数包一层(最常用, 推荐)
//   箭头函数没有自己的 this, 它里面的 this 继承自外层(此处=timer)
setTimeout(() => timer.tick(), 1000);   // ✓ 这里是 timer.tick() 隐式绑定, this=timer

// ✓ 正解二: 用 bind 显式绑定, 返回一个 this 被绑死的新函数
setTimeout(timer.tick.bind(timer), 1000);   // ✓ bind 后的函数 this 永远是 timer

// ✓ 正解三: 类里用"箭头函数定义方法"(类字段), 一劳永逸锁住 this
class Timer {
  seconds = 0;
  tick = () => {                 // ✓ 箭头函数: this 在定义时就锁定为实例, 永不丢失
    this.seconds++;
    console.log(this.seconds);
  };
}
const timer2 = new Timer();
setTimeout(timer2.tick, 1000);   // ✓ 即使"拆下来"传, this 依然是 timer2!

// ✓ 正解四(React 老写法): 构造函数里 bind
//   constructor() { this.tick = this.tick.bind(this); }

// 为什么这些能解决?
//   - 箭头函数: this 来自定义时的词法作用域, 不随调用方式变 → 锁住了。
//   - bind: 显式绑定优先级高, 生成的新函数 this 被永久固定。
//   - 共同点: 把"随调用方式漂移的 this", 变成"固定不变的 this"。

// ⚠ 常见误区:
//   - setTimeout(timer.tick.bind(timer)) ✓ 对; setTimeout(timer.tick) ✗ 错。
//   - 别在性能敏感的渲染里每次都新建箭头函数/bind(会产生新函数引用)。

// 核心: 用箭头函数包一层(this 继承外层)或 bind(显式绑定), 把 this 锁死;
//   类里可用箭头函数类字段, 让方法"拆下来"也不丢 this。

修复的思路,统一为"锁住 this"。正解一,箭头函数包一层(最常用):setTimeout(() => timer.tick(), 1000)——传给 setTimeout 的是个箭头函数,它没有自己的 this,而它内部timer.tick()(隐式绑定,this=timer),问题迎刃而解。正解二,bind 显式绑定:timer.tick.bind(timer) 返回一个 this永久绑死为 timer 的新函数。正解三,类里用箭头函数定义方法(类字段):tick = () => {...}——this 在定义时就锁定为实例、永不丢失,这样即使把方法"拆下来"传,this 依然正确,一劳永逸。(正解四:React 老写法在构造函数里 this.tick = this.tick.bind(this)。)它们为什么都管用?因为箭头函数的 this 来自定义时的词法作用域、不随调用方式变;bind 是显式绑定、优先级高、生成的新函数 this 被永久固定;共同点是——把"随调用方式漂移的 this",变成了"固定不变的 this"但也有常见误区:bind真的传进去(setTimeout(timer.tick.bind(timer)) 对,setTimeout(timer.tick) 错);别在性能敏感的渲染里每次都新建箭头函数/bind(会产生新的函数引用)。归根结底:用箭头函数包一层(this 继承外层)或 bind(显式绑定),把 this 锁死;类里可用箭头函数类字段,让方法"拆下来"也不丢 this。

第三件事:箭头函数不是万能的,它也有"反坑"

箭头函数虽好,但不能无脑用——它"没有自己的 this"这个特性,在某些场景下,反而会成为新的坑。我也梳理清楚了它的边界:

箭头函数的边界: "没有自己的 this" 有时是解药, 有时是毒药

# ✓ 箭头函数适合(正是要"继承外层 this"时):
#   - 回调里想保持外层 this: arr.map(x => this.process(x))。
#   - setTimeout/Promise.then 回调里用外层 this。
#   - 类字段方法, 锁定实例 this。

# ✗ 箭头函数不适合(恰恰需要"动态 this"时):
#   1. 对象字面量的方法:
#      const o = { name:"x", say: () => console.log(this.name) };
#      o.say();  // ✗ this 不是 o! 是外层(可能 undefined/window)。
#      → 对象方法要用普通函数: say() { ... } 或 say: function(){}
#
#   2. 原型方法 / 需要 this 指向调用实例的:
#      普通方法靠"调用时 this"才能指向不同实例, 箭头会锁死。
#
#   3. 事件处理里想用 this 指向触发元素(DOM):
#      btn.onclick = function(){ this; }  // this=btn(想要)
#      btn.onclick = () => { this; }      // ✗ this 不是 btn
#
#   4. 需要 arguments 对象的: 箭头函数没有自己的 arguments。
#
#   5. 用作构造函数: 箭头函数不能 new(没有 this/prototype)。

# 判断口诀:
#   - "希望 this 跟着外层走"(回调/类字段) → 用箭头函数。
#   - "希望 this 跟着调用者变"(对象方法/原型/DOM事件) → 用普通函数。

# 核心: 箭头函数没有自己的 this(继承外层), 回调/类字段里是解药;
#   但对象方法/原型/DOM事件/构造函数需要动态 this, 用箭头反而是坑。

箭头函数的"双刃剑"属性,我算是认清了。适合的,是"正需要继承外层 this"的场景:回调里想保持外层 this(arr.map(x => this.process(x)))、setTimeout/Promise.then 回调类字段方法锁定实例而它不适合的,恰恰是"需要动态 this"的场景:对象字面量的方法({ say: () => this.name },o.say()this 不是 o!要用普通函数 say(){});原型方法(普通方法靠"调用时 this"才能指向不同实例,箭头会锁死);DOM 事件里想让 this 指向触发元素(箭头函数的 this 不是那个元素);需要 arguments 对象的(箭头函数没有);以及用作构造函数(箭头函数不能 new)。我总结的判断口诀是:"希望 this 跟着外层走"(回调/类字段),用箭头函数;"希望 this 跟着调用者变"(对象方法/原型/DOM 事件),用普通函数归根结底:箭头函数没有自己的 this(继承外层),在回调/类字段里是解药;但对象方法/原型/DOM 事件/构造函数需要动态 this,用箭头反而是坑。

下面这张图,是这次"this 丢失"的判断与解法:

第四件事:this 四种绑定的速查对照

这次踩坑后,我把 this 的几种绑定方式,整理成一张速查表,以后看一眼调用形式就能秒判 this 是谁。

调用形式 绑定类型 this 指向
fn()(光秃秃) 默认绑定 undefined(严格)/ 全局对象
obj.fn() 隐式绑定 obj(点号前面的对象)
fn.call(x) / fn.apply(x) 显式绑定 x
fn.bind(x)() 显式绑定 x(永久固定)
new Fn() new 绑定 新创建的实例
() => {} 箭头函数 词法绑定 定义时的外层 this(不随调用变)

这张表,让"判断 this"从"玄学"变成了"看一眼调用形式"。核心就是:先看调用的"形状"——光秃秃 fn() 就是默认绑定(undefined/全局,本文的坑);obj.fn() 就看点号前面;call/apply/bind 就看你传了谁;new 就是新实例;箭头函数则跳出这套规则、看定义时的外层记住这张表,再遇到"this 到底是谁"的困惑,就能顺着"这个函数是以什么形式被调用的"这条线,一步步推出答案。它给我的最大启发是:this 之所以让无数人困惑,正是因为大家试图从"函数定义在哪"去推断它——而正确的姿势,是永远从"函数是怎么被调用的"去推断调用形式,才是 this 的唯一答案

第五件事:this 丢失在真实项目里的几种高频场景

顺着这次的教训,我把 this 丢失在真实项目里高频出没的场景,系统排查梳理了一遍。

场景 为什么 this 丢 正解
setTimeout/setInterval(obj.fn) 只传函数本身, 延迟后光秃秃调用 ()=>obj.fn() 或 obj.fn.bind(obj)
addEventListener(obj.fn) 调用时 this 指向触发元素 箭头函数包裹 / bind
数组方法 forEach/map(obj.fn) 回调被光秃秃调用 x => obj.fn(x) / 第二参数传 thisArg
Promise.then(obj.fn) 回调脱离对象调用 () => obj.fn() / bind
解构方法 const {fn}=obj fn 脱离 obj, 调用时无前缀 别解构方法, 或 bind 后再用
React 类组件事件处理 onClick={this.handle} 拆下来了 箭头函数类字段 / 构造里 bind

这张表,几乎是一份"this 丢失急救手册"。它们无一例外,都符合那个铁律:方法被"拆下来"、脱离了它的对象,然后在未来某刻被"光秃秃地"调用无论是 setTimeout/setIntervaladdEventListener(this 还会被改成触发元素)、数组的 forEach/mapPromise.then解构方法,还是 React 类组件的事件处理——它们的解法,也万变不离其宗:用箭头函数包一层(() => obj.fn()),或用 bindthis 绑死(数组方法还可以用第二个参数 thisArg;React 则推荐箭头函数类字段)。它给我的最大启发是:认清了"方法被拆下来脱离对象调用"这唯一的病根,你就不必再去死记硬背几十个"this 会在哪丢"的具体场景了——你只需要在每一次"把一个方法作为值传出去"时,条件反射地警觉一下:"它脱离对象后,this 还对吗?",然后顺手包一层箭头函数或 bind。抓住病根,胜过背诵一百个症状

第六件事:把一个方法作为值传出去时,我现在会怎么决策

现在,每当我准备把一个方法"作为值"传出去(回调、赋值、传参),脑子里都会过一遍这张决策图——核心就一问:它脱离对象后,this 还对吗?

这张图的灵魂,是把警觉前置到"传递方法的那一刻"。第一问:这个方法内部用到 this 吗?——没用到,随便传;用到了,才需要警惕。第二问:它会脱离对象被调用吗?(回调、赋值、解构、传参)——始终通过 obj.fn() 调用的,安全;会脱离对象的,this 就会丢。一旦判定危险,就this:临时一处,用箭头函数包裹bind;类方法要到处传,就定义成箭头函数类字段,一劳永逸。这套判断,让我以后传递方法时,不再凭手感、而是有章可循,核心始终是那句:这个方法,一旦脱离了它的对象,它的 this,还指向我想要的那个吗?

我立下的几条规矩

这场"this 丢失"的事故,换来了我写 JavaScript 时,刻进骨子里的几条铁律:

  1. this 是调用时决定,不是定义时绑定。看"函数怎么被调用"——尤其是"点号前面是谁",而不是它"定义在哪"。
  2. 方法被拆下来脱离对象调用,this 必丢。回调、赋值、解构、传参——只要脱离了 obj. 前缀,就要警觉。
  3. 用箭头函数或 bind 锁住 this。临时一处用 ()=>obj.fn() 或 obj.fn.bind(obj);类方法到处传用箭头函数类字段。
  4. 箭头函数没有自己的 this,继承外层。回调/类字段里是解药,但对象方法/原型/DOM事件/构造函数需要动态 this,别用它。
  5. 判断 this 从"调用形式"入手。光秃秃→默认,obj.fn→隐式,call/apply/bind→显式,new→实例,箭头→词法。
  6. 传方法前先自问:它脱离对象后 this 还对吗?抓住"方法脱离对象"这个病根,胜过背诵一百个症状。
  7. 别在热路径里反复新建 bind/箭头。会产生新函数引用,影响性能或破坏 React 的 memo 比较。

附:几行代码看清同一个函数 this 怎么变

口说无凭。下面这几行,用同一个函数、不同的调用方式,直观展示 this 是怎么"随调用而变"的,跑一遍胜过千言:

"use strict";

const obj = {
  name: "obj",
  who() { return this ? this.name : "undefined"; },
};

// 同一个 who 函数, 不同调用方式, this 完全不同:
console.log(obj.who());            // "obj"      —— 隐式绑定(obj. 调用)

const f = obj.who;                 // 把函数"拆下来"
console.log(f());                  // 报错/undefined —— 默认绑定(光秃秃调用), this 丢了!

console.log(obj.who.call({name:"X"}));  // "X"  —— 显式绑定(call 指定)
console.log(obj.who.apply({name:"Y"})); // "Y"  —— 显式绑定(apply 指定)

const bound = obj.who.bind({name:"Z"});
console.log(bound());              // "Z"        —— bind 永久绑定, 怎么调都是 Z

// 对比箭头函数: this 锁定外层, 不随调用方式变
const obj2 = {
  name: "obj2",
  whoArrow: () => (typeof this === "undefined" ? "outer" : "?"),  // this=外层(模块顶层)
};
console.log(obj2.whoArrow());      // 不是 "obj2"! —— 箭头函数 this 不指向 obj2

// setTimeout 经典坑现场:
setTimeout(obj.who, 0);            // this 丢失(拆下来传)
setTimeout(() => obj.who(), 0);    // ✓ "obj"(箭头包裹, 内部是 obj.who() 调用)

// 核心: 同一个函数, this 随"调用方式"而变(obj.who→obj, f()→丢, call/bind→指定);
//   箭头函数的 this 锁定外层不随调用变; 一跑便知"this 看调用不看定义"。

这几行代码,把"this 随调用而变"这个抽象规则,变成了肉眼可见的事实同一个 obj.who 函数:obj.who() 返回 "obj"(隐式绑定);把它拆成 const f = obj.who; f() 就丢了 this(默认绑定);call/apply 能把 this 指到任意对象;bind 之后则永久锁死——同一个函数,五种调用方式,五个不同的 this!这比任何文字,都更能说明"this 看调用、不看定义"。箭头函数 whoArrow 的对比更是点睛:即使它定义在 obj2 里面,obj2.whoArrow()this 也不指向 obj2,而是定义时的外层——这就是为什么对象方法不能用箭头函数最后那两行 setTimeout 的对比,更是把本文的坑和解法,并排摆在了一起:setTimeout(obj.who)this,而 setTimeout(() => obj.who()) 正确。这,正是我想用这几行代码,留给每一个学 JavaScript 的人的最后一课:当你对 this 感到困惑时,别去脑补、别去争论——用同一个函数,换着花样调用一遍,让 JavaScript 亲口告诉你它的 this 规则。亲手实验所得的认知,远比任何记忆都牢固;而 this 这道坎,也终将在你一次次"跑一跑、看一看"中,被你彻底踏平。

写在最后

回头看,这场由 this 丢失引发的事故,真正教给我的,是一个关于 JavaScript、乃至所有"从其他语言转过来"的学习的深刻道理:最危险的,不是那些你"不知道"的知识,而是那些你"以为自己知道、其实理解错了"的知识this 这个关键字,我在 Java、C++ 里早就用得滚瓜烂熟,它在那些语言里,老老实实地、永远指向"当前对象实例"——正是这份"我早就懂 this 了"的虚假自信,让我想当然地,把别的语言的 this 规则,直接套用到了 JavaScript 上,从而对它"调用时才动态决定"这个截然不同的灵魂,视而不见。所以,学习一门新语言,最需要警惕的,是那些"长得一样、行为却不同"的概念:它们因为"看起来眼熟",而骗过了你的警惕心,让你用旧的认知去硬套,最终在某个意想不到的地方,把你绊倒。真正的学习,不仅是"学习新东西",更是"修正那些似是而非的旧认知"——而后者,往往更难、也更重要,因为你得承认"我以为我懂的,其实不懂",才能真正地、从零开始,去理解它的本来面目对"似曾相识"保持最高的警惕,对"我早就懂了"保持一份谦逊——这,是我用一次"this 丢失"的事故,换来的、关于 JavaScript、也关于"如何学习"的、最朴素也最深刻的领悟。如果这篇复盘,能让你在下一次把一个方法传出去时,心里"咯噔"一下、多问一句"它的 this,还在吗",那我对着那个 undefined 的 this 熬的这大半天,就值了。

—— 别看了 · 2026
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理 邮箱1846861578@qq.com。
技术教程

我在 Python 的循环里批量创建了一串函数,本以为每个都记着各自的循环值,结果调用时它们竟然全都返回了同一个最后的值,我排查了大半天的复盘

2026-6-2 2:23:27

技术教程

我在 Go 的循环里用 defer 关闭打开的文件,自以为每轮都妥妥地释放了,结果批量处理几千个文件时却报了 too many open files,我排查了大半天的复盘

2026-6-2 2:34:51

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索