JavaScript 对象(千字长文)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新开坑项目:《Spring AI 项目实战》 正在持续爆肝中,基于 Spring AI + Spring Boot 3.x + JDK 21..., 点击查看 ;
 - 《从零手撸:仿小红书(微服务架构)》 已完结,基于
 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
 截止目前, 星球 内专栏累计输出 100w+ 字,讲解图 4013+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3700+ 小伙伴加入学习 ,欢迎点击围观
前言:理解 JavaScript 对象的核心价值
在 JavaScript 开发中,对象(Object)是构建复杂功能的核心工具。无论是前端框架的组件化开发,还是后端服务的数据处理,对象都扮演着“组织者”的角色。它将数据与行为封装在单一结构中,就像一个精心设计的收纳盒,既能分类存储物品,又能提供操作这些物品的工具。
对于编程初学者而言,对象可能显得抽象;但通过循序渐进的学习,可以将其转化为灵活解决问题的利器。本文将从基础概念出发,结合实际案例,深入探讨 JavaScript 对象的创建、属性管理、原型链机制等关键知识点,并提供可直接复用的代码示例。
一、对象的基本概念与创建方法
1.1 什么是 JavaScript 对象?
JavaScript 对象是键值对(Key-Value)的集合,每个键(Key)是字符串类型,值(Value)可以是任意数据类型(数字、函数、其他对象等)。例如:
const person = {
  name: "Alice",
  age: 28,
  greet: function() {
    console.log(`Hello, my name is ${this.name}`);
  }
};
- name 和 age 是数据属性(Data Properties),存储具体信息;
 - greet 是方法属性(Method Properties),定义了对象的行为。
 
1.2 对象的创建方式
方法一:字面量语法(Literal Notation)
这是最直接的方式,适合小型对象的快速创建:
const car = {
  brand: "Tesla",
  model: "Model S",
  year: 2023,
  accelerate: function(speed) {
    console.log(`加速到 ${speed} km/h`);
  }
};
方法二:构造函数(Constructor Function)
通过函数模板批量生成对象,适合创建多个同类实例:
function Book(title, author) {
  this.title = title;
  this.author = author;
  this.displayInfo = function() {
    console.log(`${this.title} by ${this.author}`);
  };
}
const book1 = new Book("JavaScript 高级程序设计", "Nicholas C. Zakas");
const book2 = new Book("你不知道的 JavaScript", "Kyle Simpson");
方法三:ES6 Class 语法
ES6 引入的类(Class)语法,使面向对象编程更直观:
class Product {
  constructor(name, price) {
    this.name = name;
    this.price = price;
  }
  calculateDiscount(discountRate) {
    return this.price * (1 - discountRate);
  }
}
const phone = new Product("iPhone 15", 999);
console.log(phone.calculateDiscount(0.1)); // 输出 899.1
二、对象的属性与方法详解
2.1 数据属性与访问器属性
JavaScript 对象的属性分为两种类型:
| 类型          | 描述                                                                 | 示例代码                          |
|---------------|----------------------------------------------------------------------|-----------------------------------|
| 数据属性      | 直接存储值,通过键名直接访问或修改                                   | person.age = 30                |
| 访问器属性    | 通过 get 和 set 方法间接操作值,常用于数据验证或计算属性           | obj.setAge(25) 或 obj.age     |
示例:使用访问器属性控制年龄的合法性
const user = {
  _age: 18,
  get age() {
    return this._age;
  },
  set age(value) {
    if (value < 0) {
      throw new Error("年龄不能为负数");
    }
    this._age = value;
  }
};
user.age = 25; // 正常赋值
console.log(user.age); // 输出 25
user.age = -5; // 抛出错误
2.2 对象方法的绑定问题
在 JavaScript 中,函数脱离对象后,this 的指向可能发生改变。例如:
const calculator = {
  value: 0,
  add: function(num) {
    this.value += num;
  }
};
const addFive = calculator.add; // 直接赋值函数
calculator.value = 10;
addFive(5); // 报错:this.value 为 undefined
解决方案:使用 bind() 明确绑定上下文,或改用箭头函数:
const addFiveBound = calculator.add.bind(calculator);
addFiveBound(5); // 正确输出 15
三、对象的继承与原型链机制
3.1 原型链(Prototype Chain)的核心思想
JavaScript 的继承是通过原型链实现的。每个对象都有一个 __proto__ 属性(非标准)指向其构造函数的原型对象(prototype)。例如:
function Animal(name) {
  this.name = name;
}
Animal.prototype.speak = function() {
  return "Animal sound";
};
const dog = new Animal("Buddy");
console.log(dog.speak()); // 输出 "Animal sound"
当访问 dog.speak() 时,若 dog 自身没有该方法,则会沿着原型链向上查找,直到找到 Animal.prototype.speak。
3.2 原型链的可视化比喻
可以将原型链想象为一个家族树:
- 对象 是家族中的成员;
 - 原型 是成员的父辈;
 - 原型链 是从自己到祖先的连续关系链。
 
例如,dog 的原型是 Animal.prototype,而 Animal.prototype 的原型是 Object.prototype,最终指向 null,形成终止条件。
四、对象与数组的关系
4.1 数组的本质是对象
JavaScript 的数组(Array)是对象的子类,其内部通过索引(0, 1, 2...)存储元素。例如:
const fruits = ["apple", "banana", "orange"];
console.log(fruits[0]); // 输出 "apple"
console.log(fruits.length); // 输出 3
但需要注意:
- 数组的 
length属性会自动更新,如fruits[5] = "grape"会将length变为 6; - 数组方法(如 
push()、map())是通过Array.prototype继承的。 
4.2 对象与数组的转换
将对象转为数组
const scores = { math: 90, english: 85 };
// 转为键值对数组
const entries = Object.entries(scores); // [ ["math", 90], ["english", 85] ]
// 转为值数组
const values = Object.values(scores); // [90, 85]
将数组转为对象
const data = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" }
];
// 转为以 id 为键的对象
const idMap = data.reduce((acc, item) => {
  acc[item.id] = item;
  return acc;
}, {}); // { 1: { ... }, 2: { ... } }
五、对象的拷贝与合并
5.1 深拷贝与浅拷贝的区别
- 浅拷贝(Shallow Copy):复制对象的引用,修改子对象会同时影响原对象。
 - 深拷贝(Deep Copy):递归复制所有嵌套对象,确保完全独立。
 
示例:浅拷贝的陷阱
const original = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, original);
shallowCopy.b.c = 3;
console.log(original.b.c); // 输出 3(原对象被修改)
实现深拷贝的方法:
function deepCopy(obj) {
  return JSON.parse(JSON.stringify(obj));
}
const deepCopyObj = deepCopy(original);
deepCopyObj.b.c = 4;
console.log(original.b.c); // 仍为 3
5.2 合并对象:Object.assign() 与展开运算符
const defaults = { theme: "light", fontSize: 14 };
const userSettings = { theme: "dark" };
// 方法一:Object.assign()
const mergedOptions1 = Object.assign({}, defaults, userSettings);
// 结果:{ theme: "dark", fontSize:14 }
// 方法二:展开运算符(ES6)
const mergedOptions2 = { ...defaults, ...userSettings };
六、ES6 新增的对象特性
6.1 对象简写语法
在构造函数或方法中,若属性名与变量名相同,可省略键名:
const name = "JavaScript";
const version = "ES6";
const feature = {
  name, // 等价于 name: name
  version, // 等价于 version: version
  isModern() { // 等价于 isModern: function() {}
    return true;
  }
};
6.2 计算属性名
使用方括号 [] 动态定义属性名:
const keyName = "price";
const product = {
  [keyName]: 299,
  ["discountedPrice"]: 269.99
};
console.log(product.price); // 输出 299
6.3 类的静态方法与继承
class MathUtil {
  static sqrt(value) {
    return Math.sqrt(value);
  }
}
// 继承父类
class AdvancedMath extends MathUtil {
  constructor() {
    super();
  }
  cube(value) {
    return value ** 3;
  }
}
console.log(AdvancedMath.sqrt(16)); // 输出 4
const math = new AdvancedMath();
console.log(math.cube(3)); // 输出 27
七、实际应用案例:构建购物车系统
7.1 需求分析
实现一个购物车对象,需支持以下功能:
- 添加商品
 - 删除商品
 - 计算总价
 - 清空购物车
 
7.2 代码实现
class ShoppingCart {
  constructor() {
    this.items = [];
  }
  addItem(item) {
    this.items.push(item);
  }
  removeItem(index) {
    this.items.splice(index, 1);
  }
  calculateTotal() {
    return this.items.reduce((sum, item) => sum + item.price, 0);
  }
  clearCart() {
    this.items = [];
  }
}
// 使用示例
const cart = new ShoppingCart();
cart.addItem({ name: "Laptop", price: 1200 });
cart.addItem({ name: "Mouse", price: 25 });
console.log(cart.calculateTotal()); // 输出 1225
cart.removeItem(0);
console.log(cart.items.length); // 输出 1
结论:掌握对象,解锁 JavaScript 的无限可能
通过本文的讲解,我们系统学习了 JavaScript 对象的创建、属性管理、继承机制及实际应用。从基础的键值对结构到复杂的原型链,对象不仅是数据的容器,更是实现复杂功能(如面向对象编程、模块化设计)的核心工具。
对于开发者而言,建议通过以下方式深化理解:
- 实践优先:尝试用对象重构现有代码,例如将散落的变量封装为对象;
 - 探索原型链:通过控制台查看对象的 
__proto__属性,理解继承关系; - 阅读源码:分析开源框架(如 React、Vue)中对象的使用场景,学习最佳实践。
 
掌握 JavaScript 对象,你将能够更优雅地组织代码逻辑,构建高效、可维护的系统。下一次面对复杂需求时,不妨让对象成为你最得力的“助手”吧!