JavaScript 对象操作:添加、删除、修改属性
JavaScript 中的对象是存储数据的核心容器,几乎所有编程场景都会用到它。掌握对象的增删改查操作,是写出高效代码的基础。本文将用最直白的方式,带你彻底搞懂 JavaScript 对象的属性操作。
对象的创建方式
在动手操作属性之前,先快速回顾几种常见的对象创建方法。
字面量创建
这是最常用的方式,直接用花括号定义:
const user = {
name: '张三',
age: 25
};
构造函数创建
使用 new Object() 语法,功能与字面量完全一致:
const car = new Object();
car.brand = '丰田';
car.color = '白色';
Object.create() 创建
这种方法可以指定一个对象作为原型:
const prototype = {
greet() {
return '你好';
}
};
const person = Object.create(prototype);
person.name = '李四';
添加属性
向 JavaScript 对象添加属性有多种方式,每种方式都有其适用场景。
点符号添加
使用点语法是最直观的方式,适合属性名是合法标识符的情况:
const book = {};
book.title = 'JavaScript高级程序设计';
book.author = 'Nicholas Zakas';
book.year = 2021;
注意:点符号后面的属性名不能以数字开头,不能包含空格或特殊字符(除了 $ 和 _)。
方括号添加
当属性名不符合标识符规则,或者属性名是变量时,必须使用方括号:
const config = {};
config['server-url'] = 'https://api.example.com';
config['max-connections'] = 100;
// 使用变量作为属性名
const propName = 'status';
config[propName] = 'active';
方括号内可以放任何表达式,计算结果会作为属性名:
const keys = ['a', 'b', 'c'];
const obj = {};
keys.forEach((key, index) => {
obj[key] = index * 10;
});
// 结果: { a: 0, b: 10, c: 20 }
批量添加属性
使用 Object.assign() 可以一次性添加多个属性:
const base = { x: 1 };
Object.assign(base, { y: 2 }, { z: 3, x: 10 });
// base 变成 { x: 10, y: 2, z: 3 }
Object.assign() 会修改第一个参数对象,并返回它。如果需要创建新对象,可以这样写:
const original = { a: 1 };
const copy = Object.assign({}, original, { b: 2 });
// original 不变,copy 是 { a: 1, b: 2 }
扩展运算符添加
ES6 提供的扩展运算符是另一种便捷方式:
const obj1 = { a: 1 };
const obj2 = { b: 2 };
const combined = { ...obj1, ...obj2 };
// combined 是 { a: 1, b: 2 }
修改属性
修改属性的本质是给已有属性重新赋值,语法与添加完全相同。
直接赋值修改
const user = { name: '王五', age: 30 };
user.age = 31;
user.name = '王六';
// user 现在是 { name: '王六', age: 31 }
条件修改
有时需要根据当前值决定如何修改,可以使用三元运算符或逻辑运算符:
const counter = { value: 0 };
counter.value = counter.value < 10 ? counter.value + 1 : 0;
// 如果值小于10则加1,否则归零
基于现有值修改
对于数值类型,可以直接使用复合赋值运算符:
const point = { x: 10, y: 20 };
point.x += 5; // point.x 变成 15
point.y *= 2; // point.y 变成 40
修改嵌套属性
访问嵌套对象时,直接赋值会触发错误(如果中间属性不存在),所以需要先确保路径存在:
const settings = {
theme: { colors: { primary: 'blue' } }
};
// 安全修改嵌套属性
settings.theme.colors.primary = 'green';
// 如果不确定结构是否存在,先创建
const data = {};
((data.options || {}).display || {}).title = '新标题';
// 或者使用可选链
data.options?.display?.title = '新标题';
删除属性
删除对象属性使用 delete 运算符,返回布尔值表示是否成功删除。
基本删除语法
const item = { name: '商品', price: 99, stock: 50 };
const result = delete item.price;
// result 是 true,item 变成 { name: '商品', stock: 50 }
注意:delete 只能删除对象自身的属性,无法删除原型链上的属性。
删除不存在的属性
删除不存在的属性不会报错,返回 true:
const obj = { a: 1 };
delete obj.b; // 返回 true,不报错
批量删除属性
JavaScript 没有直接的批量删除方法,可以通过解构赋值配合展开运算符实现:
const data = { a: 1, b: 2, c: 3, d: 4, e: 5 };
const { a, e, ...remaining } = data;
// a: 1, e: 5, remaining 是 { b: 2, c: 3, d: 4 }
或者用循环逐个删除:
const obj = { x: 1, y: 2, z: 3 };
const keysToDelete = ['x', 'z'];
keysToDelete.forEach(key => delete obj[key]);
// obj 现在是 { y: 2 }
访问属性的方法
除了点语法和方括号语法,还有几种访问属性的专业方式。
in 运算符检查属性存在
const obj = { a: 1, b: 2 };
'a' in obj; // true
'c' in obj; // false
in 会检查对象自身的属性和原型链上的属性。如果只想检查自身属性,用 hasOwnProperty():
const obj = { a: 1 };
obj.hasOwnProperty('a'); // true
obj.hasOwnProperty('toString'); // false(来自原型)
可选链操作符安全访问
当不确定嵌套结构是否存在时,用 ?. 避免报错:
const user = {};
user.address?.city; // undefined,不会报错
user.address?.city?.name; // undefined
获取所有属性名
| 方法 | 返回内容 | 自身属性 | 可枚举 | Symbol 属性 |
|---|---|---|---|---|
Object.keys() |
字符串数组 | 是 | 是 | 否 |
Object.getOwnPropertyNames() |
字符串数组 | 是 | 是/否都包含 | 否 |
Object.getOwnPropertySymbols() |
Symbol 数组 | 是 | 是/否都包含 | 是 |
Reflect.ownKeys() |
所有属性名数组 | 是 | 是/否都包含 | 是 |
const obj = { a: 1 };
Object.keys(obj); // ['a']
Object.getOwnPropertyNames(obj); // ['a']
属性描述符:精细控制属性行为
每个对象属性除了值之外,还有着一系列描述其行为的特性。通过属性描述符,可以精确控制属性的可写性、可枚举性等。
获取属性描述符
const obj = { name: '测试' };
const descriptor = Object.getOwnPropertyDescriptor(obj, 'name');
/*
descriptor 结果:
{
value: '测试',
writable: true, // 是否可修改值
enumerable: true, // 是否可被遍历
configurable: true // 是否可被删除或修改描述符
}
*/
定义属性描述符
使用 Object.defineProperty() 或 Object.defineProperties() 可以精确控制属性:
const obj = {};
// 定义一个只读属性
Object.defineProperty(obj, 'PI', {
value: 3.14159,
writable: false,
enumerable: true,
configurable: false
});
obj.PI = 100; // 静默失败,在严格模式下报错
obj.PI; // 仍然是 3.14159
三个关键特性说明
| 特性 | 作用 | 默认值(字面量创建) | 默认值(defineProperty) |
|---|---|---|---|
writable |
控制是否可修改值 | true |
false |
enumerable |
控制是否可被 for...in / Object.keys 遍历 |
true |
false |
configurable |
控制是否可被删除或重新配置 | true |
false |
创建只存不取的属性
通过省略 get 函数并设置 writable: false,可以创建一个无法读取(返回 undefined)的属性:
const obj = {};
Object.defineProperty(obj, 'secret', {
value: '123456',
writable: false,
enumerable: false,
configurable: false
});
console.log(obj.secret); // undefined
console.log('secret' in obj); // true
常见问题与解决方案
问题一:对象属性顺序
现代 JavaScript 中,整数索引属性会按数值大小排序,字符串和 Symbol 属性按创建顺序排序:
const obj = {};
obj[10] = '整数10';
obj[2] = '整数2';
obj.b = '字符串b';
obj.a = '字符串a';
obj[Symbol('s')] = 'Symbol';
Object.keys(obj); // ['2', '10', 'b', 'a'](整数索引排在前面,按数值排序)
问题二:冻结与密封
如果需要防止对象被意外修改,可以使用以下方法:
| 方法 | 禁止添加新属性 | 禁止删除现有属性 | 禁止修改属性值 | 禁止修改描述符 |
|---|---|---|---|---|
Object.freeze() |
是 | 是 | 是 | 是 |
Object.seal() |
是 | 是 | 否 | 是 |
Object.preventExtensions() |
是 | 否 | 否 | 否 |
const obj = { a: 1 };
Object.freeze(obj);
obj.a = 100; // 无效
obj.b = 2; // 无效
delete obj.a; // 无效
问题三:浅拷贝与深拷贝
直接赋值或展开运算符都是浅拷贝,只复制第一层:
const original = { a: 1, nested: { b: 2 } };
const shallow = { ...original };
shallow.nested.b = 100;
original.nested.b; // 100,也被修改了
深拷贝需要递归处理或使用结构化克隆:
// 方法一:JSON 序列化(简单场景)
const deep = JSON.parse(JSON.stringify(original));
// 方法二:结构化克隆(支持更多类型)
const deep2 = structuredClone(original);
实战示例
假设你需要实现一个配置管理功能,包含默认值、运行时修改、以及防止意外修改的需求:
class Config {
constructor(defaults) {
this._data = { ...defaults };
// 将所有默认属性设为不可枚举
Object.keys(this._data).forEach(key => {
Object.defineProperty(this, key, {
get() { return this._data[key]; },
set(value) { this._data[key] = value; },
enumerable: true,
configurable: false
});
});
}
get(key) {
return this._data[key];
}
set(key, value) {
this._data[key] = value;
}
freeze() {
Object.freeze(this._data);
}
}
// 使用示例
const config = new Config({ theme: 'dark', language: 'zh-CN' });
config.language = 'en'; // 修改成功
config.theme; // 'dark'
config.freeze(); // 冻结后无法再修改
这篇文章涵盖了 JavaScript 对象属性操作的核心知识点。理解这些基础概念,你就能在实际开发中游刃有余地处理各种对象操作场景。

暂无评论,快来抢沙发吧!