JavaScript 对象入门:从字面量到原型链的完整指南

23 阅读4分钟

JavaScript 作为一门基于对象的语言,其核心数据结构——对象(Object) ,既是组织数据的容器,也是实现面向对象编程的基石。掌握对象的创建、操作与继承机制,是迈向专业前端开发的关键一步。本文将结合你的学习笔记,系统梳理 JavaScript 对象的核心概念与最佳实践。


一、什么是 JavaScript 对象?

JavaScript 对象是一种复合数据类型,以键值对(属性和方法)的形式组织数据。它既是数据容器,也是面向对象编程的基础,支持动态添加、修改和删除属性。

与数组不同,对象的“键”(属性名)是字符串(或 Symbol),而“值”可以是任意类型:数字、字符串、函数(此时称为“方法”)、甚至其他对象。这种灵活性使其成为构建复杂应用的理想选择。


二、创建对象:字面量语法

最简洁、最常用的方式是对象字面量(Object Literal)

// 空对象
var empty = {};

// 带属性的对象
var stooge = {
  "first-name": "Jerome", // 属性名含特殊字符,必须加引号
  lastName: "Howard"      // 合法标识符,可省略引号
};

✅ 对象可嵌套

对象的值可以是另一个对象,形成树状结构:

var flight = {
    airline: "Oceanic",
    number: 815,
    departure: {
      IATA: "SYD",
      time: "2004-09-22 14:55",
      city: "Sydney"
    },
    arrival: {
      IATA: "LAX",
      time: "2004-09-23 10:42",
      city: "Los Angeles"
    }
  };

📌 命名建议:优先使用合法标识符(如 lastName),避免引号;若需保留关键字或特殊字符(如 "first-name"),再用引号。


三、检索属性:安全访问数据

可通过两种方式访问属性:

方式语法使用场景
点表示法obj.property属性名是合法标识符(推荐)
方括号obj["property"]属性名含空格/运算符,或动态计算
console.log(stooge.lastName);        // "Howard"
console.log(stooge["first-name"]);   // "Jerome"

// 动态访问
var key = "airline";
console.log(flight[key]);            // "Oceanic"

⚠️ 安全访问策略

  • 不存在的属性返回 undefined
console.log(stooge.age); // undefined
  • 用 || 设置默认值
var name = stooge.name || "Unknown";
  • 用 && 避免深层访问报错
// 安全获取 
city var city = flight.departure && flight.departure.city;

💡 现代替代方案:ES2020 引入的可选链操作符(?.  更简洁:

var city = flight.departure?.city; // 若 departure 为 null/undefined,返回 undefined

四、更新与扩展:动态性是核心优势

JavaScript 对象是动态的

  • 更新:直接赋值覆盖现有属性;
  • 扩展:赋值新属性名,自动扩容。
stooge.firstName = "Curly"; // 新增属性 
stooge.lastName = "Fine"; // 修改属性

🌟 这种“运行时可变”特性,使 JavaScript 能灵活适应各种数据结构。


五、引用传递:理解内存模型

对象通过引用来传递,永远不会被拷贝

var x = { id: 1 };
var y = x;          // y 和 x 指向同一对象
y.id = 2;
console.log(x.id);  // 2 —— 修改 y 影响了 x!

若需深拷贝,需使用 JSON.parse(JSON.stringify(obj))(仅限纯数据)或第三方库(如 Lodash)。


六、原型(Prototype):继承的奥秘

每个对象都连接到一个原型对象,并且它可以从中继承属性。

这是 JavaScript 实现继承的核心机制:

// 创建原型对象
var person = { species: "Homo sapiens" };

// 创建新对象,以 person 为原型
var student = Object.create(person);
console.log(student.species); // "Homo sapiens"(继承而来)

// 修改原型,所有实例立即可见
person.habitat = "Earth";
console.log(student.habitat); // "Earth"

⚠️ 关键原则

  • 修改对象不影响原型student.job = "Developer" 不会改变 person
  • 删除属性可能暴露原型属性
delete student.species;
console.log(student.species); // 仍为 "Homo sapiens"(从原型继承)

七、反射与枚举:探索对象内部

1. typeof 的局限性

typeof obj.prop 可判断类型,但无法区分自有属性与继承属性

2. hasOwnProperty():精准检测自有属性

console.log(student.hasOwnProperty('species')); // false(继承的)
console.log(student.hasOwnProperty('job'));     // true(自有)

✅ 安全调用(防覆盖):

console.log(student.hasOwnProperty('species')); // false(继承的)
console.log(student.hasOwnProperty('job'));     // true(自有)

✅ 安全调用(防覆盖):

Object.prototype.hasOwnProperty.call(student, 'job');
// 或现代写法
Object.hasOwn(student, 'job'); // ES2022+

3. for...in 枚举所有可枚举属性

for (var key in student) {
    if (student.hasOwnProperty(key)) { // 过滤继承属性
      console.log(key, student[key]);
    }
  }

📌 现代替代Object.keys(obj) 仅返回自有可枚举属性名数组。


八、删除属性:delete 操作符

delete student.job;
console.log(student.job); // undefined
  • 仅删除自有属性,不影响原型;
  • 可能使原型属性“浮现” (如上文 species 示例)。

九、减少全局污染:命名空间模式

全局变量削弱程序灵活性,应极力避免。

将相关变量/函数封装到单个对象中,形成命名空间(Namespace)

// ❌ 危险:多个全局变量
var userName = "Alice";
var userAge = 25;
function getUserInfo() { ... }

// ✅ 安全:单一全局对象
var MyApp = {
  user: {
    name: "Alice",
    age: 25
  },
  getUserInfo: function() { ... }
};

// 使用
MyApp.user.name;
MyApp.getUserInfo();

✅ 优势

  • 避免命名冲突;
  • 提高代码模块化;
  • 便于管理与维护。

结语:对象是 JavaScript 的灵魂

从简单的字面量到复杂的原型链,JavaScript 对象以其动态性、灵活性和强大的表达能力,支撑起现代 Web 应用的骨架。理解其核心机制——属性访问、引用传递、原型继承与反射——不仅能写出更健壮的代码,更是深入掌握框架(如 React、Vue)底层原理的基础。

记住: “Everything in JavaScript is an object” (除原始类型外)。善用对象,你便掌握了这门语言的钥匙。