JavaScript 访问对象属性
在上一章中,我们学习了 JavaScript 中对象的基本概念——它们如何允许我们将相关的数据和功能组合成单一的、有意义的单元,就像现实世界的实体一样。
对象非常强大,因为它们帮助我们组织代码并以结构化的方式表示复杂信息。但是创建对象只是第一步。要真正利用对象的力量,我们需要知道如何访问它们持有的每一条数据,即 属性 (Properties)。
在本章中,我们将深入探讨访问对象属性的两种主要方法:点符号 (Dot Notation) 和 方括号 (Bracket Notation),并理解何时以及为何使用每种方法。
1. 访问对象属性:基础知识
一旦你创建了一个包含各种属性的对象,你会经常需要检索与这些属性相关联的值。
你可以把对象想象成一个贴有标签的 盒子,里面装着更小的、贴有标签的隔间(属性),每个隔间都装着特定的物品(值)。访问属性就意味着打开主盒子,根据标签找到正确的隔间,然后取出里面的物品。
JavaScript 提供了两种主要方式来“查看”对象内部并获取属性的值:
- 点符号 (Dot Notation,
.): 这是最常见且通常首选的方法。 - 方括号 (Bracket Notation,
[]): 这提供了更大的灵活性,特别是当属性名不标准或是动态确定时。
这两种方法都允许你读取属性的值、为现有属性分配新值,甚至在对象创建后向其添加新属性。
1.1 创建我们的示例对象
在本节课中,我们将使用一个 person(人)对象作为主要示例,来演示点符号和方括号是如何工作的。这个对象将帮助我们清晰地说明不同的场景。
// 我们的示例 'person' 对象
let person = {
firstName: "Alice",
lastName: "Smith",
age: 30,
"eye color": "blue", // 带有空格的属性名
isStudent: false,
hobbies: ["reading", "hiking", "coding"], // 数组作为属性值
address: { // 嵌套对象作为属性值
street: "123 Main St",
city: "New York",
zipCode: "10001"
}
};
console.log(person);
/*
输出:
{
firstName: 'Alice',
lastName: 'Smith',
age: 30,
'eye color': 'blue',
isStudent: false,
hobbies: [ 'reading', 'hiking', 'coding' ],
address: { street: '123 Main St', city: 'New York', zipCode: '10001' }
}
*/2. 点符号 (Dot Notation, .)
点符号是访问对象属性最简单、最常用的方式。它简洁易读,是大多数情况下的默认选择。
2.1 点符号是如何工作的
要使用点符号,你需要写下对象的名字,后面跟着一个点(.),然后是你想要访问的属性名。
语法: objectName.propertyName
注意: propertyName 必须是一个有效的 JavaScript 标识符。这意味着它不能包含空格、连字符(除非它是变量名的一部分,例如 my-property 是无效的,myProperty 是有效的),也不能以数字开头。它也不能是保留的 JavaScript 关键字(如 if、for、function 等)。
2.2 使用点符号的示例
2.2.1 检索属性值
let person = {
firstName: "Alice",
lastName: "Smith",
age: 30,
isStudent: false
};
// 使用点符号访问属性
let personFirstName = person.firstName;
console.log("名字:", personFirstName); // 输出: 名字: Alice
let personAge = person.age;
console.log("年龄:", personAge); // 输出: 年龄: 30
console.log("是学生吗:", person.isStudent); // 输出: 是学生吗: false2.2.2 访问嵌套对象属性
如果一个对象属性的值是另一个对象,你可以通过 链式调用 点符号来访问嵌套对象内的属性。这允许你深入挖掘复杂的数据结构。
let person = {
firstName: "Alice",
lastName: "Smith",
address: { // 嵌套对象
street: "123 Main St",
city: "New York",
zipCode: "10001"
}
};
// 访问嵌套属性
console.log("街道:", person.address.street); // 输出: 街道: 123 Main St
console.log("城市:", person.address.city); // 输出: 城市: New York
console.log("邮编:", person.address.zipCode); // 输出: 邮编: 100012.2.3 修改现有属性值
你可以使用点符号配合赋值运算符(=)来更改现有属性的值。
let person = {
firstName: "Alice",
lastName: "Smith",
age: 30
};
console.log("原始年龄:", person.age); // 输出: 原始年龄: 30
// 更改 'age' 属性的值
person.age = 31;
console.log("新年龄:", person.age); // 输出: 新年龄: 31
// 更改 'firstName' 属性的值
person.firstName = "Alicia";
console.log("新名字:", person.firstName); // 输出: 新名字: Alicia2.2.4 添加新属性
如果你尝试为对象上不存在的属性名赋值,JavaScript 会自动为你创建该新属性。
let person = {
firstName: "Alice",
lastName: "Smith"
};
console.log(person); // 输出: { firstName: 'Alice', lastName: 'Smith' }
// 添加一个新属性 'occupation' (职业)
person.occupation = "软件开发工程师";
console.log("职业:", person.occupation); // 输出: 职业: 软件开发工程师
// 添加另一个新属性 'email'
person.email = "alice.smith@example.com";
console.log("邮箱:", person.email); // 输出: 邮箱: alice.smith@example.com
console.log(person);
/*
输出:
{
firstName: 'Alice',
lastName: 'Smith',
occupation: '软件开发工程师',
email: 'alice.smith@example.com'
}
*/2.3 点符号的局限性
点符号虽然适用于大多数情况,但它有局限性:
- 无效的标识符: 如果属性名不是有效的 JavaScript 标识符(例如,包含空格、连字符或以数字开头),则不能使用点符号。
- 动态属性名: 如果属性名存储在变量中或需要在运行时确定,你不能使用点符号。
对于这些场景,我们需要使用方括号。
3. 方括号 (Bracket Notation, [])
方括号提供了一种更灵活的方式来访问对象属性,尤其是在点符号不适用的情况下。它允许你在方括号内使用 字符串(或计算结果为字符串的表达式)来指定属性名。
3.1 方括号是如何工作的
要使用方括号,你需要写下对象的名字,后面跟着方括号([]),在括号内,你提供作为 字符串 的属性名。
语法: objectName["propertyName"]
关键点: 括号内的属性名必须是一个字符串。这个字符串可以是一个字面量字符串(例如 "age")或者是一个保存字符串值的变量。
3.2 使用方括号的示例
3.2.1 使用标准名称检索属性值
即使对于可以用点符号访问的属性名,你也可以使用方括号。这是有效的,尽管稍微繁琐一些。
let person = {
firstName: "Alice",
lastName: "Smith",
age: 30
};
// 使用带有字符串字面量的方括号访问属性
let personFirstName = person["firstName"];
console.log("名字:", personFirstName); // 输出: 名字: Alice
let personAge = person["age"];
console.log("年龄:", personAge); // 输出: 年龄: 303.2.2 访问带有无效标识符的属性
这是方括号大显身手的地方。如果属性名包含空格、连字符或以数字开头,你 必须 使用方括号。
let product = {
name: "笔记本电脑",
price: 1200,
"item category": "电子产品", // 带有空格的属性名
"product-id": "XYZ-789", // 带有连字符的属性名
"1_year_warranty": true // 以数字开头的属性名
};
// 尝试对 "item category" 使用点符号会导致错误:
// console.log(product.item category); // 语法错误 (SyntaxError)
// 正确地使用方括号访问无效标识符属性
console.log("类别:", product["item category"]); // 输出: 类别: 电子产品
console.log("产品 ID:", product["product-id"]); // 输出: 产品 ID: XYZ-789
console.log("保修:", product["1_year_warranty"]); // 输出: 保修: true3.2.3 动态属性访问(使用变量)
方括号最强大的功能或许是它能够使用 变量 来访问属性。当你直到程序运行通过时才知道确切的属性名,或者当你想要遍历属性时,这非常有用。
let person = {
firstName: "Alice",
lastName: "Smith",
age: 30
};
let propertyToAccess = "age";
// 使用变量动态访问 'age' 属性
console.log("动态访问年龄:", person[propertyToAccess]); // 输出: 动态访问年龄: 30
propertyToAccess = "firstName";
console.log("动态访问名字:", person[propertyToAccess]); // 输出: 动态访问名字: Alice
// 你甚至可以将变量直接传入之前课程(第 5 模块)中的函数
function getPropertyValue(obj, propName) {
return obj[propName]; // 这里必须使用方括号以实现动态访问
}
console.log("函数访问姓氏:", getPropertyValue(person, "lastName")); // 输出: 函数访问姓氏: Smith
let myKey = "lastName";
console.log("函数访问姓氏 (变量):", getPropertyValue(person, myKey)); // 输出: 函数访问姓氏 (变量): Smith3.2.4 使用方括号修改和添加属性
就像点符号一样,你可以在赋值运算符左侧使用方括号来修改现有属性或添加新属性。当新属性名可能包含空格或需要动态生成时,这特别有用。
let person = {
firstName: "Alice",
age: 30
};
// 使用方括号修改 'age'
person["age"] = 31;
console.log("新年龄:", person.age); // 输出: 新年龄: 31
// 添加一个新属性 'middle name' (必须用方括号,因为有空格)
person["middle name"] = "Marie";
console.log("中间名:", person["middle name"]); // 输出: 中间名: Marie
let newPropertyKey = "email";
let newPropertyValue = "alice@example.com";
// 使用变量动态添加新属性
person[newPropertyKey] = newPropertyValue;
console.log("邮箱:", person.email); // 输出: 邮箱: alice@example.com
console.log(person);
/*
输出:
{
firstName: 'Alice',
age: 31,
'middle name': 'Marie',
email: 'alice@example.com'
}
*/4. 何时使用哪种符号
这里有一个快速总结,帮助你决定使用哪种符号:
| 特性 | 点符号 (.) | 方括号 ([]) |
|---|---|---|
| 常见用途 | 最常见,标准属性名的默认选择 | 用于动态访问,或带有特殊字符的属性名 |
| 属性名格式 | 必须是有效的 JavaScript 标识符(无空格、连字符,不能以数字开头) | 可以是任何字符串,包括带有空格、连字符或数字的字符串 |
| 动态访问 | 否 | 是 (可以使用变量) |
| 可读性 | 通常更易读、更简洁 | 稍微繁琐,但在特定情况下是必需的 |
经验法则:
- 默认使用点符号:当你提前知道属性名且它是一个有效的 JavaScript 标识符时。它更干净、更易读。
- 使用方括号:当:
- 属性名包含特殊字符(如空格、连字符)。
- 属性名存储在变量中,需要动态访问。
- 属性名是一个数字(例如
let obj = {100: "value"}; obj[100];)。
5. 实战示例与演示
让我们将所学知识结合起来,通过模拟真实数据处理的更复杂场景来演示。
5.1 示例 1:管理库存物品
想象一下你正在构建一个简单的库存系统。
let inventory = {
"item101": {
name: "笔记本电脑",
quantity: 15,
"unit price": 1200, // 带有空格的属性
tags: ["电子产品", "电脑"]
},
"item102": {
name: "鼠标",
quantity: 50,
"unit price": 25,
tags: ["电子产品", "外设"]
},
"item103": {
name: "键盘",
quantity: 30,
"unit price": 75,
tags: ["电子产品", "外设"]
}
};
// 使用两种符号访问属性
// 1. 使用点符号获取 item101 的名称 (可行,因为 'name' 是有效标识符)
console.log("Item 101 名称:", inventory.item101.name); // 输出: Item 101 名称: 笔记本电脑
// 2. 使用点符号获取 item102 的数量
console.log("Item 102 数量:", inventory.item102.quantity); // 输出: Item 102 数量: 50
// 3. 获取 item103 的单价。这需要方括号,因为有空格。
console.log("Item 103 单价:", inventory.item103["unit price"]); // 输出: Item 103 单价: 75
// 4. 更新 item101 的数量
inventory.item101.quantity = 10;
console.log("Item 101 新数量:", inventory.item101.quantity); // 输出: Item 101 新数量: 10
// 5. 为 item102 添加新属性 'location'
inventory.item102.location = "仓库 A";
console.log("Item 102 位置:", inventory.item102.location); // 输出: Item 102 位置: 仓库 A
// 6. 基于变量动态访问物品
let itemId = "item103";
let priceKey = "unit price"; // 带有空格的键
console.log(`动态访问 ${itemId} 的价格:`, inventory[itemId][priceKey]); // 输出: 动态访问 item103 的价格: 75
// 7. 向库存添加新物品 (创建新的顶层属性)
let newItemId = "item104";
inventory[newItemId] = {
name: "显示器",
quantity: 20,
"unit price": 300,
tags: ["电子产品", "显示设备"]
};
console.log("新 Item 104 名称:", inventory.item104.name); // 输出: 新 Item 104 名称: 显示器这个例子清楚地表明,在处理属性名可能不总是完美的 JavaScript 标识符,以及需要灵活地动态访问数据的真实场景中,这两种符号都是至关重要的。
5.2 示例 2:访问 API 响应数据(假设场景)
想象一下你从 Web API 调用接收数据。这些数据通常以对象形式出现,你需要访问特定的信息片段。
// 模拟 API 响应对象
let apiResponse = {
status: "success",
data: {
userId: "user_abc_123",
username: "coder_beginner",
"last_login_date": "2023-10-26", // 带有下划线的属性
profile: {
"full_name": "John Doe",
email: "john.doe@example.com",
"account-status": "active" // 带有连字符的属性
},
permissions: ["read", "write", "delete"]
},
timestamp: Date.now()
};
// 使用点符号访问顶层属性
console.log("API 状态:", apiResponse.status); // 输出: API 状态: success
console.log("用户 ID:", apiResponse.data.userId); // 输出: 用户 ID: user_abc_123
// 访问嵌套属性,有些需要方括号
// 由于下划线,虽然技术上可以用点符号,但为了演示混用场景我们这里也可以用方括号,
// 或者如果是 'last-login-date' (连字符) 则必须用方括号。
console.log("上次登录日期:", apiResponse.data["last_login_date"]); // 输出: 上次登录日期: 2023-10-26
// 访问 profile 对象内的 'full_name'
console.log("全名:", apiResponse.data.profile["full_name"]); // 输出: 全名: John Doe
// 使用方括号访问 'account-status',因为有连字符
console.log("账户状态:", apiResponse.data.profile["account-status"]); // 输出: 账户状态: active
// 访问 'permissions' 数组(它是一个属性)中的元素
console.log("第一个权限:", apiResponse.data.permissions[0]); // 输出: 第一个权限: read这个 API 示例展示了遇到混合属性命名约定是多么常见,这使得点符号和方括号对于处理外部数据都不可或缺。