添加键值对后推入JSON对象到数组,却仅保留最后一组值的问题
这是个非常典型的JavaScript引用类型陷阱!我来帮你理清问题根源,以及修复方法。
问题原因
在JavaScript中,对象是引用类型,这意味着当你执行var tdata = data时,并没有复制data对象本身,只是让tdata变量指向了和data完全相同的内存地址。
所以在forEach循环里,每次修改tdata.target_user,实际上都是在修改同一个原始的data对象。而你推到followers_data数组里的,全都是这个同一个对象的引用。当循环结束后,这个对象的target_user已经被最后一次循环覆盖为'balk',所以数组里所有元素显示的都是这个最终值。
你看到每次循环里console.log(tdata)是正确的,只是因为当时恰好修改了对象属性,但后续循环会继续修改同一个对象,最终数组里的所有引用都会指向这个被修改后的对象。
解决方案
解决核心是每次循环创建一个独立的新对象,而不是复用同一个对象的引用。这里有几种简单的实现方式:
方法1:使用对象展开运算符(推荐,ES6+)
通过{...data}快速创建一个新对象,复制原data的所有属性:
console.log("Followers") console.log(his_followers); var data = { createdAt: 1555674703 /* some more key pair values exist here */ } his_followers.forEach(uid => { // 创建新对象,复制data的所有属性 var tdata = {...data}; tdata.target_user = uid.followed_by console.log('tdata') console.log(tdata); followers_data.push(tdata) }) console.log('Followers data') console.log(followers_data);
方法2:使用Object.assign
如果需要兼容更低版本的JavaScript,可以用Object.assign来创建新对象:
var tdata = Object.assign({}, data);
注意事项
如果data对象内部还有嵌套的对象/数组,那上面的方法属于浅拷贝,需要用到深拷贝(比如递归复制、JSON.parse(JSON.stringify(data)),但后者有局限性,比如无法处理函数、Symbol等)。不过从你的代码看,data是简单的扁平结构,浅拷贝完全足够。
修改后,每次循环的tdata都是独立的新对象,修改它们的target_user不会互相影响,最终followers_data数组里的元素就会显示正确的对应值了。
内容的提问来源于stack exchange,提问作者Code Tree

