跟着 MDN 学JavaScript day_25:JavaScript对象基础技能测试实战解析
引言:从理论到实践的跨越
在前一篇文章中,我们系统学习了JavaScript对象的基础知识。然而,编程学习的一个核心原则是理论知识必须通过实践来巩固。阅读代码和理解概念只是第一步,亲自动手编写代码、解决问题才是真正掌握知识的关键。
MDN为对象基础章节设计了四个循序渐进的技能测试题目,从基本的属性访问和方法调用开始,逐步深入到创建复杂的嵌套对象、使用this实现方法复用,最后引入构造函数来消除代码重复。
一、技能测试一:对象的属性访问与方法调用
1.1 任务描述
提供一个简单的 cat 对象字面量,包含 name、breed、color 属性和一个 greeting 方法。要求完成三项操作。
const cat = {
name: "Bertie",
breed: "Cymric",
color: "white",
greeting: function () {
console.log("Meow!");
},
};
const catName; // 等待赋值
// 在此处补全代码
1.2 三项操作要求
| 序号 | 要求 | 使用方式 |
|---|---|---|
| ① | 将 name 属性的值存储到 catName 变量中 |
括号表示法 |
| ② | 运行 greeting 方法 |
点表示法 |
| ③ | 将 color 属性值更新为 "black" |
点表示法 |
1.3 代码实现
const cat = {
name: "Bertie",
breed: "Cymric",
color: "white",
greeting: function () {
console.log("Meow!");
},
};
// ① 使用括号表示法获取 name 属性值
const catName = cat["name"];
// ② 使用点表示法调用 greeting 方法
cat.greeting();
// ③ 更新 color 属性值
cat.color = "black";
1.4 设计意图分析
这道题在一组操作中有意识地引导同时使用点表示法和括号表示法,强化对比认知:
| 方式 | 语法 | 本题用途 | 适用场景 |
|---|---|---|---|
| 点表示法 | cat.greeting() |
调用方法 & 更新属性 | 属性名已知的字面量 |
| 括号表示法 | cat["name"] |
获取属性值赋值给变量 | 属性名在变量中或动态计算 |
两种方式可以并存使用,开发者应根据具体场景选择最合适的方式。
二、技能测试二:构建复杂嵌套对象
2.1 任务描述
创建一个表示乐队的对象字面量。这个对象不仅包含基本属性,更关键的是包含一个 albums 数组——数组中的每个元素本身又是一个包含 name 和 released 属性的对象。这种嵌套结构模拟了真实开发中常见的JSON数据组织形式。
let bandInfo;
// 在此处补全代码
2.2 构建嵌套对象
const band = {
name: "The Beatles",
nationality: "British",
genre: "Rock",
members: 4,
formed: 1960,
split: 1970,
albums: [
{
name: "Please Please Me",
released: 1963,
},
{
name: "Abbey Road",
released: 1969,
},
],
};
数据结构可视化:
band (Object)
├── name: "The Beatles"
├── nationality: "British"
├── genre: "Rock"
├── members: 4
├── formed: 1960
├── split: 1970
└── albums: (Array)
├── [0] (Object)
│ ├── name: "Please Please Me"
│ └── released: 1963
└── [1] (Object)
├── name: "Abbey Road"
└── released: 1969
2.3 链式访问:构建 bandInfo 字符串
这道题目的真正难点在于最后一步——构建 bandInfo 字符串,需要综合运用多种知识:
bandInfo = `${band.name}是一支来自${band.nationality}的${band.genre}乐队,成立于${band.formed}年,共有${band.members}名成员。他们于${band.split}年解散。他们的首张专辑《${band.albums[0].name}》于${band.albums[0].released}年发行。`;
band.albums[0].name 链式访问路径拆解:
band → 整个 band 对象
.albums → 访问对象属性 → 得到数组 [{...}, {...}]
[0] → 数组索引访问 → 得到第一个专辑对象 {name: "Please...", ...}
.name → 访问对象属性 → 得到 "Please Please Me"
| 步骤 | 语法 | 类型转换 | 结果 |
|---|---|---|---|
| 1 | band.albums |
Object → Array | [{...}, {...}] |
| 2 | band.albums[0] |
Array → Object | {name: "Please Please Me", released: 1963} |
| 3 | band.albums[0].name |
Object → String | "Please Please Me" |
2.4 综合技能运用
| 技能 | 在本题中的应用 |
|---|---|
| 模板字符串 | 用 `...${}...` 拼接多段信息 |
| 点表示法 | band.name、band.nationality 等 |
| 数组索引 | band.albums[0] 访问第一个元素 |
| 嵌套链式访问 | band.albums[0].name 穿透多层 |
| 对象字面量 | 创建 band 对象和 albums 子对象 |
三、技能测试三:this关键字实现方法复用
3.1 任务描述
重写 cat 对象的 greeting 方法,使其输出 "Hello, said Bertie the Cymric." 格式。核心约束:重写后的方法必须能在任何相同结构的 cat 对象上正常工作,不能硬编码具体的属性值。
const cat = {
name: "Bertie",
breed: "Cymric",
color: "white",
greeting: function () {
// 在此处重写方法
},
};
const cat2 = {
name: "Elfie",
breed: "Aphrodite Giant",
color: "ginger",
greeting: function () {
// 一样的重写
},
};
3.2 代码实现
const cat = {
name: "Bertie",
breed: "Cymric",
color: "white",
greeting: function () {
console.log(`Hello, said ${this.name} the ${this.breed}.`);
},
};
const cat2 = {
name: "Elfie",
breed: "Aphrodite Giant",
color: "ginger",
greeting: function () {
console.log(`Hello, said ${this.name} the ${this.breed}.`);
},
};
cat.greeting(); // "Hello, said Bertie the Cymric."
cat2.greeting(); // "Hello, said Elfie the Aphrodite Giant."
3.3 this 的运行时绑定机制
cat.greeting() 被调用
↓
this = cat(调用者)
↓
this.name → "Bertie"
this.breed → "Cymric"
↓
输出:"Hello, said Bertie the Cymric."
cat2.greeting() 被调用
↓
this = cat2(调用者)
↓
this.name → "Elfie"
this.breed → "Aphrodite Giant"
↓
输出:"Hello, said Elfie the Aphrodite Giant."
| 对比 | 硬编码写法 | this 写法 |
|---|---|---|
| cat 的方法 | cat.name → 只能用于 cat |
this.name → 自适应调用者 |
| cat2 的方法 | 必须重写为 cat2.name |
完全相同的代码 |
| 复用性 | ❌ 不可复用 | ✅ 代码完全相同 |
相同的代码产生了不同的输出——这正是面向对象编程中多态的体现。
3.4 暴露的问题
greeting 方法的定义在两个对象中完全重复了。这违反了编程中的重要原则——DRY(Don’t Repeat Yourself)。代码重复会带来维护问题:修改格式需要在两处分别修改,容易遗漏和出错。
四、技能测试四:构造函数消除代码重复
4.1 问题根源
在任务三中,每个 cat 对象都需要复制一份完全相同的 greeting 方法代码。当需要维护或创建更多 cat 时,问题会急剧恶化:
修改 greeting 格式 → 需要修改每一个 cat 对象
新增 cat3 → 又要复制粘贴一遍
新增 cat4 → 再复制粘贴一遍
... → 代码膨胀、难以维护
4.2 解决方案:构造函数
构造函数允许定义一个"模板",然后使用 new 关键字创建任意数量的对象实例。按照惯例,构造函数以大写字母开头:
function Cat(name, breed, color) {
this.name = name;
this.breed = breed;
this.color = color;
this.greeting = function () {
console.log(`Hello, said ${this.name} the ${this.breed}.`);
};
}
const cat = new Cat("Bertie", "Cymric", "white");
const cat2 = new Cat("Elfie", "Aphrodite Giant", "ginger");
cat.greeting(); // "Hello, said Bertie the Cymric."
cat2.greeting(); // "Hello, said Elfie the Aphrodite Giant."
4.3 new 关键字的工作机制
new Cat("Bertie", "Cymric", "white")
↓
① 创建一个空对象 → {}
② 将 this 绑定到新对象 → this = {}
③ 执行构造函数代码:
this.name = "Bertie"
this.breed = "Cymric"
this.color = "white"
this.greeting = function() { ... }
④ 自动返回新对象 → return this(无需手动 return)
4.4 重构前后对比
| 维度 | 重构前(对象字面量×N) | 重构后(构造函数) |
|---|---|---|
| 创建方式 | const cat = { name: "...", ... } |
const cat = new Cat("...") |
greeting 定义 |
每个对象各写一遍 | 只写一次 |
| 修改格式 | 需要在每处修改 | 只改一处 |
| 新增实例 | 复制粘贴全部代码 | 一行代码 new Cat(...) |
| 代码量 | O(n) 随实例数增长 | O(1) 恒定 |
4.5 构造函数的本质价值
构造函数 = 对象创建模板
Cat(name, breed, color)
|
| new 关键字
|
┌─────┼─────┬─────┐
▼ ▼ ▼ ▼
cat cat2 cat3 catN
每个实例自动拥有相同的结构和方法
数据不同但行为一致
这种集中管理、分散使用的模式是面向对象编程的核心优势——一处定义,处处生效。
五、四道题目学习路径总结
| 测试 | 核心技能 | 复杂度 | 关键收获 |
|---|---|---|---|
| 测试一 | 属性访问 + 方法调用 | ⭐ | 点表示法与括号表示法的场景选择 |
| 测试二 | 嵌套对象创建与链式访问 | ⭐⭐ | 多层数据结构穿透与模板字符串 |
| 测试三 | this 关键字运行时绑定 |
⭐⭐⭐ | 编写与具体数据解耦的通用方法 |
| 测试四 | 构造函数消除代码重复 | ⭐⭐⭐ | DRY原则 + 抽象思维 + 批量创建 |
学习路径图
测试一:基本操作
│ 属性读取、方法调用、值更新
│ 点表示法 ↔ 括号表示法
▼
测试二:嵌套结构
│ 对象包含数组、数组包含对象
│ 链式访问:band.albums[0].name
▼
测试三:this 复用
│ 方法代码与具体数据分离
│ 暴露问题:代码重复
▼
测试四:构造函数
│ 消除重复、模板化创建
│ DRY原则 → 一处定义,处处生效
总结
JavaScript的对象系统远比这四道题所展示的要丰富和复杂——原型链、类语法、getter/setter、属性描述符等高级主题还在前方等待探索。但扎实掌握这些基础知识至关重要,因为它们是理解更高级概念的基石。
| 知识要点 | 一句话总结 |
|---|---|
| 点 vs 括号表示法 | 属性名已知用点,属性名为变量用括号 |
| 嵌套链式访问 | obj.prop[index].nested 逐层穿透 |
this |
指向调用方法的对象,实现方法复用 |
| 构造函数 | new ClassName() 批量创建同类型对象,消除重复 |
编程概念的学习需要经历认识 → 理解 → 应用 → 反思的完整循环。当我们能够熟练使用对象字面量组织数据、使用this编写通用方法、使用构造函数创建实例家族时,就已经具备了继续深入学习的坚实基础。
更多推荐

所有评论(0)