跟着 MDN 学JavaScript day_24:JavaScript对象基础完全指南
引言:为什么需要对象
在JavaScript编程的世界里,对象是最核心的概念之一。当你开始构建稍微复杂的应用程序时,很快就会意识到,使用独立分散的变量来存储相关联的数据是多么笨拙和低效。
constpersonName="张三";constpersonAge=28;constpersonOccupation="工程师";随着应用规模的增长,这些零散的变量不仅难以管理,还容易导致命名冲突和代码混乱。如果要表示多个人,情况会变得更加糟糕。
对象应运而生,它提供了一种优雅的方式,将相关的数据和功能组织在一起,形成一个逻辑上独立的单元:
constperson={name:"张三",age:28,occupation:"工程师"};对象反映了我们对现实世界的自然认知方式——将一个人视为具有各种属性和行为的整体,而不是孤立的特征集合。
一、对象基础:什么是对象字面量
对象本质上是一个包含相关数据和方法的集合。在对象的语境中:数据项被称为属性,函数被称为方法。
创建对象最简单直接的方式是使用对象字面量语法——通过手动编写对象的内容来创建对象。
1.1 空对象
constperson={};虽然空对象本身做不了什么,但它标志着我们开始使用一种全新的数据组织方式。
1.2 完整的对象示例
constperson={name:["Bob","Smith"],age:32,bio:function(){console.log(`${this.name[0]}${this.name[1]}现在${this.age}岁了。`);},introduceSelf:function(){console.log(`你好!我是${this.name[0]}。`);},};1.3 ES6 方法简写
当对象的成员是函数时,可以省略冒号和function关键字:
constperson={name:["Bob","Smith"],age:32,bio(){console.log(`${this.name[0]}${this.name[1]}现在${this.age}岁了。`);},introduceSelf(){console.log(`你好!我是${this.name[0]}。`);},};1.4 访问对象成员
person.name;// ["Bob", "Smith"]person.name[0];// "Bob"person.age;// 32person.bio();// "Bob Smith 现在 32 岁了。"person.introduceSelf();// "你好!我是 Bob。"对象字面量的典型使用场景:需要传输一系列结构化的相关数据项时(如向服务器发送请求),发送一个对象比分别发送多个独立数据项更有效率。
二、点表示法:访问对象属性的主要方式
点表示法是访问对象属性和方法最常用、最直观的方式。对象名充当命名空间的角色,为内部成员提供上下文:
person.age;// 访问属性person.bio();// 调用方法2.1 链式访问(子命名空间)
当一个对象成员本身又是一个对象时,可以继续使用点表示法深入访问:
constperson={name:{first:"Bob",last:"Smith",},age:32,bio(){console.log(`${this.name.first}${this.name.last}现在${this.age}岁了。`);},introduceSelf(){console.log(`你好!我是${this.name.first}。`);},};person.name.first;// "Bob"person.name.last;// "Smith"| 层级 | 访问路径 | 结果 |
|---|---|---|
| 第一层 | person | 整个对象 |
| 第二层 | person.name | {first: "Bob", last: "Smith"} |
| 第三层 | person.name.first | "Bob" |
⚠️ 修改对象的内部结构时,所有引用该结构的代码都需要同步更新。例如:数组索引 → 嵌套对象属性名。
三、括号表示法:动态访问对象属性
括号表示法作为点表示法的替代方案,语法与数组访问相似:
person["age"];person["name"]["first"];3.1 对象本质上是关联数组
| 数组类型 | 键(Key) | 映射 |
|---|---|---|
| 普通数组 | 数字索引 | 0 → "hello" |
| 对象 | 字符串键 | "name" → "Bob" |
3.2 括号表示法的独特优势:动态属性名
点表示法只接受字面量成员名,而括号表示法可以接受变量作为属性名:
constperson={name:["Bob","Smith"],age:32,};functionlogProperty(propertyName){console.log(person[propertyName]);}logProperty("name");// ["Bob", "Smith"]logProperty("age");// 32| 方式 | 适用场景 |
|---|---|
点表示法person.age | 属性名在编写代码时已知(大多数情况) |
括号表示法person["age"] | 属性名保存在变量中,运行时动态确定 |
四、设置对象成员:不仅仅是更新
通过点表示法或括号表示法,不仅可以查询对象成员的值,还可以设置或更新它们。
4.1 更新已有属性
person.age=45;person["name"]["last"]="Cratchit";4.2 动态创建新成员
即便某个属性在对象定义时不存在,也可以在程序运行中通过赋值添加:
person["eyes"]="hazel";person.farewell=function(){console.log("再见!");};person["eyes"];// "hazel"person.farewell();// "再见!"4.3 括号表示法动态设置成员名
属性名本身也可以是变量,在运行时才确定:
constmyDataName="height";constmyDataValue="1.75m";person[myDataName]=myDataValue;person.height;// "1.75m"实际应用:从输入框获取属性名和属性值,动态添加到对象中:
constmyDataName=nameInput.value;constmyDataValue=nameValue.value;person[myDataName]=myDataValue;// 点表示法无法实现!五、"this"关键字:上下文引用的奥秘
在对象的方法定义中,this指向当前代码运行时所在的对象——即调用该方法的对象实例。
constperson={name:["Bob","Smith"],introduceSelf(){console.log(`你好!我是${this.name[0]}。`);},};5.1 this 的核心价值:代码复用
当只有一个对象时,this和直接使用对象名没有实质区别。但当存在多个对象时,this的优势就凸显出来:
constperson1={name:"Chris",introduceSelf(){console.log(`你好!我是${this.name}。`);},};constperson2={name:"Deepti",introduceSelf(){console.log(`你好!我是${this.name}。`);},};person1.introduceSelf();// "你好!我是 Chris。"person2.introduceSelf();// "你好!我是 Deepti。"使用对象名引用(❌ 不灵活): person1.introduceSelf() → console.log(`你好!我是 ${person1.name}。`) person2.introduceSelf() → console.log(`你好!我是 ${person2.name}。`) → 方法定义不同,无法复用 使用 this 引用(✅ 灵活): person1.introduceSelf() → this = person1 → this.name = "Chris" person2.introduceSelf() → this = person2 → this.name = "Deepti" → 方法定义完全相同,this 自动适配调用者this让同样的方法代码对不同对象产生不同输出,实现了代码复用和行为的多态。
六、构造函数:批量创建对象的工厂
6.1 对象字面量的局限
当需要创建多个结构相同的对象时,对象字面量需要重复编写大量相同代码:
// 重复劳动,低效且容易出错constsalva={name:"Salva",introduceSelf(){...}};constfrankie={name:"Frankie",introduceSelf(){...}};constchris={name:"Chris",introduceSelf(){...}};6.2 工厂函数(过渡方案)
functioncreatePerson(name){constobj={};obj.name=name;obj.introduceSelf=function(){console.log(`你好!我是${this.name}。`);};returnobj;}constsalva=createPerson("Salva");constfrankie=createPerson("Frankie");salva.introduceSelf();// "你好!我是 Salva。"frankie.introduceSelf();// "你好!我是 Frankie。"6.3 构造函数(标准做法)
构造函数与普通函数的区别在于使用new关键字调用。按照惯例,构造函数以大写字母开头:
functionPerson(name){this.name=name;this.introduceSelf=function(){console.log(`你好!我是${this.name}。`);};}// 使用 new 关键字调用constsalva=newPerson("Salva");constfrankie=newPerson("Frankie");salva.introduceSelf();// "你好!我是 Salva。"frankie.introduceSelf();// "你好!我是 Frankie。"6.4 new 关键字自动完成的四个步骤
① 创建一个空对象 → {} ② 将 this 绑定到新对象 → this = {} ③ 运行构造函数中的代码 → this.name = "Salva"; ... ④ 返回新对象 → return this(自动完成)6.5 三种创建方式对比
| 方式 | 语法 | 适用场景 | 代码复用 |
|---|---|---|---|
| 对象字面量 | const obj = { ... } | 单个对象、传输数据 | ❌ 无法复用 |
| 工厂函数 | function create() { return {...} } | 少量相似对象 | ⚠️ 较冗长 |
| 构造函数 | new Person() | 批量创建同类型对象 | ✅ 标准做法 |
七、你一直在使用对象:无处不在的内置对象
回顾之前学过的JavaScript知识,许多熟悉的功能实际上都是通过对象来实现的。
7.1 String 对象
constmyString="Hello,World";myString.split(",");// ["Hello", "World"]每次创建字符串时,该字符串都会被自动创建为String的实例,因此可以访问原型上的split()、toUpperCase()、trim()等方法。
7.2 Document 对象(DOM)
constmyDiv=document.createElement("div");constmyVideo=document.querySelector("video");页面加载完毕后,Document的实例document被创建,代表整个页面的结构、内容和功能。
7.3 Array 对象
constarr=[1,2,3];arr.push(4);// Array 实例的方法arr.map(x=>x*2);// 同上7.4 Math 对象
Math.PI;// 3.14159...(静态属性)Math.random();// 随机数(静态方法)Math是内置对象,不需要实例化即可直接使用。
7.5 需要手动实例化的 API
constmyNotification=newNotification("你好!");不同API的设计思想不同,但底层原理相通:它们都是基于JavaScript的对象系统构建的。
总结
| 知识点 | 核心内容 |
|---|---|
| 对象字面量 | { key: value }创建单个对象,适合传输结构化数据 |
| 点表示法 | person.age,属性名已知时使用 |
| 括号表示法 | person["age"],属性名为变量时使用 |
| 动态设置成员 | person[varName] = value,属性名运行时确定 |
this关键字 | 指向调用方法的对象实例,实现代码复用和多态 |
| 构造函数 | new Person()批量创建同类型对象 |
| 内置对象 | String、Array、Document、Math等都是对象 |
对象的核心价值:将相关的属性和方法封装在一起,形成逻辑上独立的单元。对象使我们将信息安全地锁在它们自己的包内,防止命名冲突和数据混乱。
在掌握了对象基础之后,下一步将探索JavaScript更具特色的概念——原型。原型是JavaScript实现对象继承的基本方式,让对象能够从其他对象继承属性和方法,进一步扩展代码复用的可能性。
还在为 JavaScript 代码写得像“意大利面条”、逻辑混乱难以维护而头秃?收藏本文持续跟进,后续将系统分享 JS 高效语法糖、浏览器兼容与 Polyfill 实战、手写核心源码解析、常见坑点避雷指南,从基础语法到进阶逻辑一站式打通,助你快速提升前端开发硬实力!
