使用Object.defineProperty提取JS对象details属性失败问题排查
问题分析:提取对象details属性失败的原因及解决方法
问题场景
现有如下JavaScript对象:
const allData = {"aaa": {"xxx": {},"details": {"111": {"a": 1}}},"bbb": {"yyy": {},"details": {"222": {"a": 10}}},"ccc": {"zzz": {},"details": {"333": {"a": 100}}},"ddd": {"kkk": {},"details": {"444": {"a": 1000}}}};
需要将每个子对象的details属性提取到新对象allDetails中,编写的代码如下:
allDetails={}; $.each(allData, function (nameCont, valCont){ console.dir(valCont.details); Object.defineProperty(allDetails, nameCont, valCont.details); }); console.dir(allDetails);
预期结果为:
{"aaa": {"111": {"a": 1}},"bbb": {"222": {"a": 10}},"ccc": {"333": {"a": 100}},"ddd": {"444": {"a": 1000}}}
但实际运行后未得到预期结果,问题出在哪里?
问题原因
核心错误是误用了Object.defineProperty的参数:Object.defineProperty的第三个参数必须是一个属性描述符对象,它需要包含value、enumerable、writable等合法的描述符键,而不是直接传入要赋值的属性值。
你直接把valCont.details作为第三个参数传入,代码会把这个对象里的键(比如"111")当成描述符的属性,但这些不是合法的描述符字段,导致无法正确为allDetails添加属性,自然得不到预期结果。
另外,即使你传入的描述符里有value,默认情况下用Object.defineProperty添加的属性是不可枚举的,后续遍历或打印时可能看不到,也需要显式设置enumerable: true。
解决方法
有两种简单的修正方式:
方式1:直接属性赋值(推荐)
不需要用Object.defineProperty,直接通过对象属性赋值的方式添加,这是最直观的写法:
const allData = {"aaa": {"xxx": {},"details": {"111": {"a": 1}}},"bbb": {"yyy": {},"details": {"222": {"a": 10}}},"ccc": {"zzz": {},"details": {"333": {"a": 100}}},"ddd": {"kkk": {},"details": {"444": {"a": 1000}}}}; const allDetails = {}; $.each(allData, function(nameCont, valCont){ allDetails[nameCont] = valCont.details; }); console.dir(allDetails);
方式2:正确使用Object.defineProperty
如果一定要用这个方法,必须传入标准的属性描述符对象,显式指定value和enumerable等属性:
const allData = {"aaa": {"xxx": {},"details": {"111": {"a": 1}}},"bbb": {"yyy": {},"details": {"222": {"a": 10}}},"ccc": {"zzz": {},"details": {"333": {"a": 100}}},"ddd": {"kkk": {},"details": {"444": {"a": 1000}}}}; const allDetails = {}; $.each(allData, function(nameCont, valCont){ Object.defineProperty(allDetails, nameCont, { value: valCont.details, enumerable: true, // 必须设置为true,否则属性不可枚举 writable: true, configurable: true }); }); console.dir(allDetails);
内容的提问来源于stack exchange,提问作者Francesco G.
相关产品推荐
相关产品推荐

