JavaScript 对象操作实战指南:从基础到高级技巧
2025-07-08 07:52:29作者:裘晴惠Vivianne
前言
在 JavaScript 开发中,对象操作是最基础也是最重要的技能之一。本文将深入探讨 JavaScript 对象的各种操作技巧,从简单的键值遍历到复杂的代理模式应用,帮助开发者掌握对象操作的核心技术。
1. 嵌套对象键值遍历
处理嵌套对象时,递归是最常用的方法。下面是一个打印嵌套对象所有键值的函数:
function keyValuePrinter(obj) {
for (let key in obj) {
if (typeof obj[key] !== "object") {
console.log("[" + key + " : " + obj[key] + "]");
} else {
keyValuePrinter(obj[key]);
}
}
}
技术要点:
- 使用
typeof
检查属性类型 - 递归处理嵌套对象
for...in
循环遍历对象属性
2. 对象清空方法
清空对象有两种常见方式:
// 方法1:删除所有属性
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
delete obj[key];
}
}
// 方法2:创建新对象并继承原型
const newObj = {};
Object.setPrototypeOf(newObj, obj);
注意事项:
- 方法1会保留原型链
- 方法2创建的是全新对象,只继承原型
3. 深拷贝实现方案
深拷贝是 JavaScript 中的常见需求,以下是几种实现方式:
// 浅拷贝方法
Object.assign({}, obj);
{ ...obj };
// 深拷贝方法
JSON.parse(JSON.stringify(obj));
// 递归深拷贝函数
function deepCopy(obj) {
if (!obj) return obj;
const copyObj = {};
for (const key in obj) {
if (typeof obj[key] !== "object" || Array.isArray(obj[key]))
copyObj[key] = obj[key];
else copyObj[key] = deepCopy(obj[key]);
}
return copyObj;
}
注意事项:
- JSON 方法会丢失函数和特殊对象类型
- 递归方法可以处理复杂嵌套结构
4. 对象属性访问控制
通过 getter 和 setter 可以精确控制对象属性的访问:
// 使用 defineProperty
const obj = { marks: 0 };
Object.defineProperty(obj, "marks", {
set(value) {
if (value < 0) throw new Error("Marks cant be less than zero");
marks = value;
},
get() {
return marks;
},
});
// 使用 get/set 语法糖
const obj = {
_marks: 0,
set marks(value) {
if (value < 0) throw new Error("Marks cant be less than zero");
this._marks = value;
},
get marks() {
return this._marks;
},
};
5. 只读属性实现
创建只能设置一次的属性:
function userObjectCreator(id) {
const obj = {};
Object.defineProperty(obj, "userid", {
value: id,
writable: false,
});
return obj;
}
6. 对象序列化过滤
安全地序列化对象,排除敏感信息:
const obj = {
id: 1,
username: "John",
password: "secret",
email: "john@email.com",
};
// 方法1:使用替换函数
JSON.stringify(obj, (key, value) =>
key === "password" ? undefined : value
);
// 方法2:指定属性白名单
JSON.stringify(obj, ["id", "username", "email"]);
7. 迭代器模式实现
创建自定义迭代器:
function makeIterator(array) {
let nextIndex = 0;
return {
next: function() {
return nextIndex < array.length
? { value: array[nextIndex++], done: false }
: { done: true };
},
};
}
8. 方法链式调用
实现流畅接口:
const obj = {
id: 1,
displayId() {
console.log("Id: " + this.id);
return this;
},
displayName() {
console.log("Name: " + this.username);
return this;
}
};
obj.displayId().displayName();
9. 高级对象模式
访问计数器
function counterObject() {
const symCounter = Symbol("counter");
return {
[symCounter]: 0,
get counter() { return ++this[symCounter]; },
set counter() { throw new Error("Cannot set counter"); }
};
}
类数组对象
const arrayLikeObject = {
length: 0,
push: function(item) {
Array.prototype.push.call(this, item);
},
pop: function() {
Array.prototype.pop.call(this);
}
};
10. 对象深度比较
function deepEqual(obj1, obj2) {
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) return false;
for (const key of keys1) {
const val1 = obj1[key];
const val2 = obj2[key];
const areObjects = typeof val1 === "object" && typeof val2 === "object";
if ((areObjects && !deepEqual(val1, val2)) ||
(!areObjects && val1 !== val2)) {
return false;
}
}
return true;
}
11. 类与面向对象
class Employee {
constructor(id, name) {
this.id = id;
this.name = name;
}
setSalary(base, variable) {
this.salary = base + variable;
}
}
12. 代理高级应用
只读现有属性
const readOnlyObj = new Proxy(obj, {
set(target, key, value) {
if (target.hasOwnProperty(key)) {
throw new Error("Object properties are read-only");
}
target[key] = value;
}
});
范围检查
const range = new Proxy({ start: 10, end: 50 }, {
has(target, value) {
return value >= target.start && value <= target.end;
}
});
25 in range; // true
13. 循环引用处理
检测循环引用
function doesObjectHaveCircularRef(obj) {
try {
JSON.stringify(obj);
return false;
} catch {
return true;
}
}
消除循环引用
function removeCircularRef(obj) {
const set = new WeakSet([obj]);
(function iterateObj(obj) {
for (let key in obj) {
if (typeof obj[key] === "object") {
if (set.has(obj[key])) delete obj[key];
else {
set.add(obj[key]);
iterateObj(obj[key]);
}
}
}
})(obj);
}
14. 动态嵌套属性
function ProxyObject(obj) {
return new Proxy(obj, {
get: (target, property) => {
if (!(property in target)) {
target[property] = new ProxyObject({});
}
return target[property];
},
});
}
const obj = new ProxyObject({});
obj.x.y.z = "nested value"; // 自动创建嵌套结构
结语
本文涵盖了 JavaScript 对象操作的各个方面,从基础到高级技巧。掌握这些技术将大大提升你在日常开发中处理复杂对象结构的能力。建议读者在实际项目中尝试应用这些模式,并根据具体需求进行调整和优化。