Skip to content

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()) 的局限:不能处理函数、undefinedDate(会变成字符串)、循环引用。有复杂需求时,使用专门的深拷贝库。

四、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);