Appearance
14|JavaScript 对象与 JSON
JavaScript 的对象是一组键值对的集合,和 Python 的字典概念接近。但 JavaScript 对象的用法更深入——不仅是数据容器,还是面向对象编程的基础。JSON(JavaScript Object Notation)则是对象的一种文本表示格式,是前后端数据交换的事实标准。
一、对象基础
创建对象
js
// 对象字面量(最常用)
const server = {
hostname: "web-01",
ip: "192.168.1.10",
status: "running",
};
// 构造函数(不常用)
const obj = new Object();
obj.name = "test";访问属性
js
// 点语法(属性名符合标识符规则时)
console.log(server.hostname); // "web-01"
// 方括号语法(属性名含特殊字符或变量时)
console.log(server["ip"]); // "192.168.1.10"
const field = "status";
console.log(server[field]); // "running"属性名是字符串,即使写成裸字(hostname),也会被自动转成 "hostname"。如果属性名不符合标识符规则(含空格、连字符、数字开头等),必须用方括号:
js
const data = {
"server-name": "web-01",
"uptime-seconds": 3600,
};
console.log(data["server-name"]);修改与增删
js
server.status = "stopped"; // 修改
server.env = "production"; // 新增
delete server.env; // 删除delete 删除对象属性,不影响原型链上的同名属性。
属性简写
变量名和属性名相同时可以简写:
js
const hostname = "web-01";
const ip = "192.168.1.10";
// 简写
const server = { hostname, ip };
// 等价于 { hostname: hostname, ip: ip }计算属性名
js
const key = "status";
const server = {
hostname: "web-01",
[key]: "running", // 属性名由变量决定
};二、遍历对象
for...in
遍历对象的所有可枚举属性(包括继承来的属性):
js
for (const key in server) {
console.log(`${key}: ${server[key]}`);
}通常需要过滤掉继承属性:
js
for (const key in server) {
if (server.hasOwnProperty(key)) {
console.log(`${key}: ${server[key]}`);
}
}Object.keys / values / entries
js
Object.keys(server); // ["hostname", "ip", "status"]:所有键
Object.values(server); // ["web-01", "192.168.1.10", "running"]:所有值
Object.entries(server); // [["hostname", "web-01"], ...]:键值对数组Object.entries 配合解构遍历:
js
for (const [key, value] of Object.entries(server)) {
console.log(`${key}: ${value}`);
}三、对象引用与复制
对象赋值传递的是引用,不是副本:
js
const a = { port: 8080 };
const b = a;
b.port = 9090;
console.log(a.port); // 9090,a 也被修改了浅拷贝
js
// 方法 1:展开运算符
const copy1 = { ...server };
// 方法 2:Object.assign
const copy2 = Object.assign({}, server);浅拷贝只复制第一层。如果属性值是对象,复制的是引用:
js
const original = { name: "web-01", meta: { env: "prod" } };
const copy = { ...original };
copy.meta.env = "dev";
console.log(original.meta.env); // "dev",原始对象也被改了深拷贝
js
// 方法 1:JSON 序列化(简单场景)
const deep = JSON.parse(JSON.stringify(original));
// 方法 2:structuredClone(现代浏览器)
const deep2 = structuredClone(original);JSON.parse(JSON.stringify()) 的局限:不能处理函数、undefined、Date(会变成字符串)、循环引用。有复杂需求时,使用专门的深拷贝库。
四、JSON
JSON 是一种文本格式,语法和 JavaScript 对象字面量类似,但有严格限制:
| 特性 | JavaScript 对象 | JSON |
|---|---|---|
| 键名 | 可以不加引号 | 必须用双引号 |
| 字符串 | 单双引号均可 | 只能用双引号 |
| 尾随逗号 | 允许 | 不允许 |
| 值类型 | 任意 | 仅 string、number、boolean、null、object、array |
| 注释 | 允许 | 不允许 |
| 函数 | 可以作为值 | 不支持 |
序列化
js
const server = {
hostname: "web-01",
port: 8080,
active: true,
meta: null,
};
const jsonString = JSON.stringify(server);
// '{"hostname":"web-01","port":8080,"active":true,"meta":null}'格式化输出(缩进):
js
JSON.stringify(server, null, 2);反序列化
js
const data = JSON.parse('{"hostname":"web-01","port":8080}');
console.log(data.hostname); // "web-01"处理循环引用
js
const a = {};
const b = { ref: a };
a.ref = b; // 循环引用
JSON.stringify(a); // TypeError: Converting circular structure to JSON需要自定义 replacer 函数处理:
js
const seen = new WeakSet();
const json = JSON.stringify(a, (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return "[Circular]";
}
seen.add(value);
}
return value;
});五、常见错误
用点语法访问含特殊字符的属性名
js
const data = { "server-name": "web-01" };
// 错误
console.log(data.server-name); // NaN(被解析为 data.server - name)
// 正确
console.log(data["server-name"]);误以为对象赋值是复制
js
const defaults = { timeout: 30, retries: 3 };
const config = defaults; // 引用,不是副本
config.timeout = 60;
console.log(defaults.timeout); // 60,原始对象也被改了
// 正确:先复制
const config = { ...defaults };JSON 解析不捕获异常
js
// 错误:用户输入可能不是合法 JSON
const data = JSON.parse(userInput); // 可能抛 SyntaxError
// 正确:加 try/catch
let data;
try {
data = JSON.parse(userInput);
} catch (err) {
console.error("JSON 解析失败:", err.message);
data = {};
}在 JSON 中使用单引号
js
// 错误:JSON 标准规定字符串和键名必须用双引号
const bad = "{'name': 'web-01'}";
JSON.parse(bad); // SyntaxError
// 正确
const good = '{"name": "web-01"}';
JSON.parse(good);