JavaScript对象属性提升机制是什么?附代码执行疑问
JavaScript对象属性赋值不符合预期的原因分析
咱们先把你的代码格式化一下,看着更清晰:
function setOptions(obj, options) { if (!obj.hasOwnProperty('options')) { obj.options = obj.options ? create(obj.options) : {}; } for (var i in options) { obj.options[i] = options[i]; } return obj.options; } var x={}; setOptions(x, {prop1:2}); console.log(x); setOptions(x,{prop1:3}); console.log(x);
首先得澄清一个关键误区:JavaScript里根本没有“对象属性提升”这回事!所谓的“提升(Hoisting)”仅针对这些场景:
- 函数声明会被提升
var声明的变量会被提升(但变量的赋值不会)let/const的声明会被提升,但存在暂时性死区,无法在赋值前访问
对象的属性只有你通过.或[]语法显式赋值时才会被添加到对象上,不存在提前“冒出来”的情况。你的问题本质是代码逻辑和预期不匹配,咱们一步步拆解:
核心问题:属性挂载的层级错了
你预期第一次调用后x会直接拥有prop1:2,第二次更新为prop1:3,但实际代码里,你是把属性挂载到了obj.options这个子对象上,而不是obj本身。
第一次调用时:
x是空对象,没有options自有属性,所以进入if分支,给x添加options属性(赋值为空对象,因为此时obj.options是undefined,走else分支)- 然后遍历传入的
{prop1:2},把prop1赋值给x.options,所以最终x的结构是{ options: { prop1: 2 } }
第二次调用时:
x已经有了options自有属性,所以跳过if分支- 直接遍历新的
{prop1:3},把x.options.prop1更新为3,最终x是{ options: { prop1: 3 } }
这就是实际输出和你预期不符的根本原因——你想把属性挂在x上,但代码挂到了x.options上。
额外注意:create函数的不确定性
代码里用到的create如果不是原生Object.create,那它的行为也可能影响结果,但从现有逻辑看,即使是原生Object.create,第一次调用时obj.options是undefined,还是会赋值为空对象,所以不影响核心问题。
修正方案
如果你确实想让x直接拥有prop1属性,修改函数逻辑,把属性直接挂载到obj上就行:
function setOptions(obj, options) { for (var i in options) { obj[i] = options[i]; } return obj; } var x={}; setOptions(x, {prop1:2}); console.log(x); // 输出 { prop1: 2 } setOptions(x,{prop1:3}); console.log(x); // 输出 { prop1: 3 }
要是你本来就想维护obj.options这个子对象,那你的代码逻辑是没问题的,只是预期和实际逻辑不匹配,此时两次输出的x都会包含嵌套的options对象,第二次prop1也会被正确更新。
内容的提问来源于stack exchange,提问作者APL
相关产品推荐
相关产品推荐

