javascript解构赋值无法提取原型链属性,因其仅遍历对象自有可枚举属性;需手动提取原型属性构造新对象后解构,且注意不可枚举属性和getter的执行特性。

JavaScript中无法直接用解构赋值提取原型链上的属性,因为解构操作只作用于对象自身的可枚举属性,不遍历原型链。
为什么解构不能访问原型链属性
解构赋值本质上是语法糖,底层调用的是对象的 own property keys(自有属性键),即 Object.keys() 或 for...in 中排除继承属性的部分(for...in 会遍历继承属性,但解构不使用它)。即使属性在原型上存在且可访问(如 obj.toString),只要不是对象自身属性,解构就忽略它。
-
const { toString } = {};→ 报错:toString is not defined(因为空对象自身无toString) -
const obj = {}; const { toString } = obj;→ 同样报错,尽管obj.toString在运行时有效
绕过限制的常用方法:先“扁平化”到自身
若需解构原型链上的属性,可先将目标属性显式复制到临时对象(或直接读取后赋值),再解构。这不是“自动提取”,而是主动桥接:
- 用
Object.assign({}, obj)浅拷贝(仅自有属性,仍不包含原型属性)→ 不适用 - 正确做法:手动提取所需属性,构造新对象:
const { toString, hasOwnProperty } = Object.assign({}, { toString: obj.toString, hasOwnProperty: obj.hasOwnProperty }); - 更简洁写法(推荐):
const { toString, hasOwnProperty } = { toString: obj.toString, hasOwnProperty: obj.hasOwnProperty };
结合作用域变量提升可读性与复用性
可在函数作用域或块级作用域中预先提取,避免重复访问原型:
function inspect(obj) {<br> const { constructor, toString } = { constructor: obj.constructor, toString: obj.toString };<br> return `${constructor.name}: ${toString.call(obj)}`;<br>}- 对多个对象统一处理时,可封装为工具函数:
const protoPick = (obj, ...keys) => Object.fromEntries(keys.map(key => [key, obj[key]]));<br>const { valueOf, toLocaleString } = protoPick(arr, 'valueOf', 'toLocaleString');
注意陷阱:不可枚举属性和 setter/getter
即使属性在原型上是可访问的,若其描述符中 enumerable: false(如 Object.prototype.toString),也无法被 Object.keys() 或解构捕获 —— 这正是为何必须显式读取。另外,若原型属性是 getter,解构会执行 getter 并获取返回值,但不会保留 getter 本身。
const proto = { get foo() { console.log('get!'); return 42; } };<br>Object.setPrototypeOf(obj, proto);<br>const { foo } = { foo: obj.foo }; // 输出 'get!',foo = 42- 解构得到的是值,不是响应式绑定,也不触发后续 getter
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











