JavaScript 对象如何遍历与复制?Object.keys、assign 与 structuredClone 用法
JavaScript 对象如何遍历与复制Object.keys、assign 与 structuredClone 用法【免费下载链接】33-js-concepts 33 JavaScript concepts every developer should know.项目地址: https://gitcode.com/GitHub_Trending/33/33-js-concepts当你拿到一个 JavaScript 对象需要枚举它的属性做日志、汇总或转换或者需要拿一份可独立修改的副本浅拷贝或深拷贝而不影响原对象时Object构造器上的静态方法就是 33-js-concepts 项目文档给出的工具路径用Object.keys()、Object.values()、Object.entries()遍历用Object.assign()做浅拷贝/合并用structuredClone()做深拷贝。这篇项目文档同时附带一组 vitest 测试object-methods.test.js可以实际跑起来核对每一步的行为是否符合文档描述。准备条件一个支持这些方法的 JS 运行环境浏览器或 Node.js。其中structuredClone()是 2022 年才加入浏览器和 Node.js 的文档指出它取代了此前JSON.parse(JSON.stringify(obj))的变通写法——后者对Date、Map、Set和循环引用都会失效。若要在本仓库中跑验证测试需要 Node.js 环境依赖已在package.json的 devDependencies 中声明vitest 4.x。第一步用 keys / values / entries 遍历对象这三个方法把对象转成数组供循环或转换使用。以文档中的示例对象为例const user { name: Alice, age: 30, city: NYC } const keys Object.keys(user) console.log(keys) // [name, age, city] const values Object.values(user) console.log(values) // [Alice, 30, NYC] const entries Object.entries(user) console.log(entries) // [[name, Alice], [age, 30], [city, NYC]]选哪个取决于你要什么方法返回适用时机Object.keys(obj)[key1, key2, ...]只需要属性名Object.values(obj)[value1, value2, ...]只需要值Object.entries(obj)[[key1, value1], ...]键和值都要需要强调的边界这三个方法只返回自身own可枚举属性会跳过原型链上的继承属性和不可枚举属性。如果需要包括不可枚举属性用Object.getOwnPropertyNames()const arr [1, 2, 3] Object.keys(arr) // [0, 1, 2] Object.getOwnPropertyNames(arr) // [0, 1, 2, length]length是数组的不可枚举属性所以Object.keys()看不到它。可选分支用 entries fromEntries 转换键Object.fromEntries()是Object.entries()的逆操作两者配合数组方法可以整体变换对象。文档给出的模式是把键全部转大写const upperCased Object.fromEntries( Object.entries(user).map(([key, value]) [key.toUpperCase(), value]) ) console.log(upperCased) // { NAME: Alice, AGE: 30, CITY: NYC }同样地用filter可以按值类型筛掉属性const product { name: Laptop, price: 999, inStock: true, sku: LP001 } const stringsOnly Object.fromEntries( Object.entries(product).filter(([key, value]) typeof value string) ) console.log(stringsOnly) // { name: Laptop, sku: LP001 }第二步用 Object.assign 做浅拷贝与合并JavaScript 对象按引用赋值Object.assign()把所有可枚举自身属性从源对象复制到目标对象const target { a: 1 } const source { b: 2 } Object.assign(target, source) console.log(target) // { a: 1, b: 2 }两种常见用法// 克隆以空对象为目标 const original { name: Alice, age: 30 } const clone Object.assign({}, original) clone.name Bob console.log(original.name) // Alice — 原对象不受影响 // 合并多个对象后面的源覆盖前面 const defaults { theme: light, fontSize: 14 } const userPrefs { theme: dark } const settings Object.assign({}, defaults, userPrefs) console.log(settings) // { theme: dark, fontSize: 14 }关键限制这是浅拷贝。嵌套对象仍是共享引用文档中的示例直接演示了这个陷阱const original { name: Alice, address: { city: NYC } } const clone Object.assign({}, original) clone.address.city LA console.log(original.address.city) // LA — 两边都变了顶层属性独立了改clone.name不影响original.name但address这个嵌套对象是同一个引用。如果嵌套属性必须独立用下一步的structuredClone()。第三步用 structuredClone 做深拷贝structuredClone()创建真正的深拷贝嵌套对象一并独立const original { name: Alice, address: { city: NYC } } const clone structuredClone(original) clone.address.city LA console.log(original.address.city) // NYC — 原对象保持不变除了嵌套对象它还能正确处理循环引用大多数内置类型如Date、Map、Set、ArrayBufferconst data { date: new Date(2024-01-01), items: new Set([1, 2, 3]) } const clone structuredClone(data) console.log(clone.date instanceof Date) // true console.log(clone.items instanceof Set) // true它不能克隆的东西文档明确列出函数DOM 节点属性描述符getter/setter 会变成普通值原型链克隆出来的是普通对象。包含函数时直接抛错const obj { greet: () Hello // Function } structuredClone(obj) // Throws: DataCloneError浅拷贝还是深拷贝怎么选文档给出的对照表方法深度速度适用时机Object.assign()浅快合并对象、无嵌套对象Spread{...obj}浅快快速克隆、无嵌套对象structuredClone()深慢嵌套对象必须相互独立注意{...obj}与Object.assign({}, obj)等价同样是浅拷贝——不要因为写法不同就以为它解决了嵌套共享的问题。跑仓库测试验证行为上面的示例值都可以在本仓库的测试中逐一核对。测试位于 tests/beyond/objects-properties/object-methods/object-methods.test.js测试环境为 Node见 vitest.config.js。在仓库根目录执行npm install npm testnpm test对应 package.json 中的test: vitest run会跑全部测试。如果只想核对对象方法这一部分把 vitest 指向该测试文件npx vitest run tests/beyond/objects-properties/object-methods/object-methods.test.js测试断言与文档示例一一对应几个关键判断点Object.keys({ name: Alice, age: 30, city: NYC })返回[name, age, city]Object.values(scores).reduce(...)对{ math: 95, science: 88, history: 92 }求和得到275浅拷贝示例中clone.address.city LA之后original.address.city也是LA嵌套共享的实证structuredClone的深拷贝示例中修改clone.address.city后original.address.city仍为NYCstructuredClone克隆含函数的对象会抛错测试用expect(() structuredClone(obj)).toThrow()断言不可枚举属性验证用Object.defineProperty把enumerable设为false后Object.keys/Object.values/Object.entries都只返回可枚举属性。测试全部通过即说明当前运行环境的行为与文档一致。已知的边界与限制Object.keys()/values()/entries()跳过继承属性和不可枚举属性要看全用Object.getOwnPropertyNames()看 Symbol 键用Object.getOwnPropertySymbols()。Object.assign()只拷贝顶层嵌套对象仍是共享引用。structuredClone()遇到函数会抛DataCloneError不能用于含函数、DOM 节点的对象克隆结果不带原型链getter/setter 会退化为普通值。structuredClone()要求运行环境在 2022 年之后浏览器和 Node.js 均已加入更老的环境中文档指出需要回退到JSON.parse(JSON.stringify(obj))之类的变通写法但要清楚它无法处理Date、Map、Set和循环引用。想继续深入属性枚举、描述符等底层机制可以看仓库中同系列的 property-descriptors.mdx想理解原型与继承看 object-creation-prototypes.mdx。【免费下载链接】33-js-concepts 33 JavaScript concepts every developer should know.项目地址: https://gitcode.com/GitHub_Trending/33/33-js-concepts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考