JavaScript中对象数组内this指向异常:为何输出100及如何实现独立this
先还原一个匹配你场景的示例代码,方便理解问题本质:
// 原对象obj1 const obj1 = { value: 100, // 数组里的箭头函数依赖this innerFuncs: [() => console.log(this.value)] }; // 目标对象obj2,复用obj1的数组 const obj2 = { value: 200, innerFuncs: obj1.innerFuncs }; // 调用后控制台输出100,而非obj2的200 obj2.innerFuncs[0]();
核心原因:this的绑定规则
这里的关键在于箭头函数的this绑定特性:箭头函数不会自主绑定this,它的this永远指向定义时所在的上下文。
当obj1被创建时,innerFuncs里的箭头函数是在obj1的对象字面量环境中定义的,此时的this指向obj1。这个绑定是永久的——不管后续把这个函数放到哪个对象里调用,它都会始终指向obj1,自然输出的是obj1的value:100。
如果是普通函数的情况(比如数组里是function() { console.log(this.value); }),调用obj2.innerFuncs[0]()时,普通函数的this会指向全局对象(非严格模式)或undefined(严格模式),除非你手动绑定上下文。但你提到输出是100,所以大概率是用了箭头函数,或者函数被提前绑定了obj1的this。
如何让obj2拥有自身独立的this?
既然你无法在obj2中单独创建完整的对象,那可以通过以下几种方案复用原数组的同时,让函数指向obj2的this:
方案1:调用时手动绑定this
每次调用函数时,用call/apply指定this指向obj2:
obj2.innerFuncs[0].call(obj2); // 输出200
优点是简单直接,缺点是每次调用都要手动处理,适合调用频率低的场景。
方案2:包装原数组,通过bind批量绑定
给obj2加一个方法,返回绑定了自身this的函数数组(注意原数组里必须用普通函数,箭头函数无法重新绑定this):
const obj1 = { value: 100, getFuncs() { return [function() { console.log(this.value); }]; // 用普通函数 } }; const obj2 = { value: 200, getBoundFuncs() { // 把原数组里的每个函数都绑定到obj2的this return obj1.getFuncs().map(func => func.bind(this)); } }; obj2.getBoundFuncs()[0](); // 输出200
这个方案可以一次性处理所有函数,后续调用直接用绑定后的版本即可。
方案3:用Proxy自动绑定this
如果不想手动处理,可以用Proxy拦截数组的访问,自动返回绑定了obj2 this的函数:
const obj1 = { value: 100, innerFuncs: [function() { console.log(this.value); }] }; const obj2 = { value: 200, get innerFuncs() { return new Proxy(obj1.innerFuncs, { get(target, prop) { const val = target[prop]; // 只要是函数,就自动绑定obj2的this return typeof val === 'function' ? val.bind(this) : val; } }); } }; obj2.innerFuncs[0](); // 输出200
这个方案最自动化,只要访问obj2的innerFuncs,里面的函数都会自动绑定obj2的this,适合需要频繁复用的场景。
关键注意点
如果原数组里是箭头函数,上述方案2和3都无法生效——因为箭头函数的this是不可修改的,所以必须先把原数组里的箭头函数改成普通函数,才能重新绑定this。
内容的提问来源于stack exchange,提问作者KingCoder11

