ES6 类方法、箭头函数与 this 指向的特殊行为及用例结果差异解析
逐案例实际输出参考
在浏览器非严格模式控制台中执行全量代码,输出顺序为:
1: 12: 13: undefined4: 15: 1(全量执行场景下)
单独新开标签页仅运行案例5时,输出为5: undefined
前置核心规则
所有输出逻辑都基于两条固定的this绑定规则,不存在例外:
- 箭头函数的this:完全捕获定义位置的外层词法作用域的this,后续任何调用方式都无法修改它的指向,箭头函数本身没有独立的this。
- 普通函数的this:和定义位置无关联,完全由调用时的触发方式决定:
- 直接以
fn()形式无关联调用时,非严格模式下this指向全局window对象,严格模式下this为undefined。 - 以
obj.fn()形式调用时,this指向调用语法中前置的对象obj。
- 直接以
分场景逻辑解析
案例1、案例2的等价性确认
你对两个案例的判断完全正确:对象字面量中getX: function(){}的普通方法定义,和getX(){}的简写方法定义,在this绑定、作用域逻辑上没有任何差异。
两个案例中,getX都以obj.getX()的形式调用,因此getX内部的this分别指向对应的obj1、obj2对象;内部的inner是箭头函数,捕获外层getX作用域的this,因此访问的this.x就是对象自身的x属性值1,输出符合预期。
案例3的输出逻辑
getX本身就是定义在全局作用域下的箭头函数,它捕获的this就是全局window对象;内部的inner同样是箭头函数,继续捕获外层getX作用域的this,也就是window。由于全局对象上没有提前定义x属性,因此输出3: undefined。
如果代码运行在严格模式或ES模块环境下,箭头函数捕获的外层this会为undefined,访问.x时会直接抛出类型错误。
案例4、案例5的核心差异与误解澄清
这是最容易产生认知偏差的部分,要先明确:普通函数不存在“继承外层作用域this”的特性,两个案例中的内部函数都是普通函数,this完全独立由调用方式决定,本质逻辑没有任何区别,只是环境的巧合让结果看起来出现了差异。
案例4的实际执行流程
- 函数
a以全局直接调用的形式执行,非严格模式下,a内部的this指向全局window对象。 - 执行
this.x = 1时,实际是给全局window对象挂载了值为1的x属性。 - 内部的
b是普通函数,以直接b()的形式无关联调用,非严格模式下它的this同样指向全局window对象。 b内部访问的this.x,本质是读取window.x的值,也就是之前a函数赋值的1,最终输出4: 1。
整个过程不存在this从a传递到b的继承逻辑,只是a和b的this碰巧指向了同一个全局对象,才让结果看起来像是发生了继承。
案例5的实际执行流程
getX是通过obj5.getX()的形式调用的,因此getX内部的this确实指向obj5对象,该对象的x属性值为1。- 但
getX内部的inner是普通函数,不会捕获外层getX作用域的this。 inner以直接inner()的形式无关联调用,非严格模式下它的this指向全局window对象,和外层getX的this指向完全无关。inner内部访问的this.x,本质是读取window.x的值,而不是obj5.x。
为什么单独跑案例5和全量跑的结果不一样?
核心原因是全局环境的属性污染:
单独新开标签页运行案例5时,全局window上没有已定义的x属性,因此window.x为undefined,输出5: undefined。
按顺序执行全部代码时,案例4的a()执行已经给window.x赋值为1,轮到案例5执行时,inner内部访问的this.x就是这个被前面代码污染的全局属性,值为1,看起来就像是inner继承了getX的this,本质是巧合。
如果要让案例5的inner正确拿到obj5的x值,有三种常规实现方式:
- 把内部的
inner改成箭头函数,自动捕获外层getX的this指向 - 在getX内部用
const self = this存下this引用,在inner中通过self.x访问属性 - 调用inner时手动绑定this:
inner.call(this)
内容的提问来源于stack exchange,提问作者Vaibhav Agarwal

