javascript为何存在this指向问题【教程】

JavaScript 的 this 指向调用者而非定义时上下文;call/apply 立即执行并指定 this,bind 返回永久绑定新函数;箭头函数无 this,词法继承外层普通函数的 this;对象方法、事件回调等应避免使用箭头函数。

JavaScript 的 this 不是指向“函数定义时的上下文”,而是取决于“函数被谁调用”——这是所有指向问题的根源。

为什么 callapplybind 能改 this

它们直接干预函数执行时的调用上下文:

  • call(obj, arg1, arg2) 立即执行,参数逐个传入
  • apply(obj, [arg1, arg2]) 立即执行,参数用数组传
  • bind(obj, arg1) 返回新函数,this 永久绑定为 obj

    ,后续调用无法覆盖

注意:bind 绑定后,再用 call 也无法改变其 this(箭头函数同理,但原因不同)。

箭头函数为何没有自己的 this

它不创建执行上下文,而是沿作用域链向上找外层普通函数的 this 值——本质是词法绑定。

常见误用场景:

  • 对象方法写成箭头函数:obj = { fn: () => console.log(this) }this 指向全局或 undefined(严格模式)
  • 事件回调中想访问实例,却用了箭头函数,结果 this 不是组件实例

解决办法:对象方法、生命周期钩子、事件处理器,优先用普通函数声明。

定时器和回调里 this 丢失的典型表现

例如:setTimeout(obj.method, 100) 中,method 被单独提取为函数引用,调用时 this 指向全局(非严格)或 undefined(严格)。

可行修复方式:

  • bindsetTimeout(obj.method.bind(obj), 100)
  • 用箭头函数包裹:setTimeout(() => obj.method(), 100)
  • 在类中提前绑定:this.handleClick = this.handleClick.bind(this)(构造函数内)
  • 现代写法:类字段 + 箭头函数:handleClick = () => { ... }(Babel / TS 支持)

最易忽略的一点:this 绑定发生在“调用时”,而不是“赋值时”或“传递时”。哪怕你把 obj.fn 赋给一个变量,再调用,也已经脱离了原对象——这个断连过程悄无声息,调试时得盯住调用形式。