深入理解 JavaScript 对象:从入门到精通

在 JavaScript 的世界里,有一句话广为流传------"万物皆对象"。这不仅仅是一句口号,更是理解 JavaScript 编程的核心。无论是我们常用的数组、函数,还是自定义的数据结构,几乎都可以被视为对象。本文将带你系统梳理 JS 对象的基础知识,帮助你打下坚实的 JavaScript 编程基础。

一、什么是对象?

对象(Object)是 JavaScript 中最重要的数据类型之一。它是一组无序的相关属性和方法的集合。每个属性由键(key)和值(value)组成,值可以是任意类型的数据,包括基本类型、对象、函数等。

举个例子:

js 复制代码
let person = {
  name: "张三",
  age: 25,
  sayHello: function() {
    console.log("你好,我是" + this.name);
  }
};

在上面的代码中,person 就是一个对象,包含了 nameage 两个属性和一个 sayHello 方法。

二、创建对象的三种方式

JavaScript 提供了多种创建对象的方法,常见的有三种:

1. 字面量方式

这是最常用、最简洁的方式。直接用大括号包裹属性和方法即可。

js 复制代码
let obj = {
  key1: "value1",
  key2: "value2"
};

2. 使用 new Object()

通过 new 关键字和 Object 构造函数创建对象,然后再为对象添加属性。

js 复制代码
let obj = new Object();
obj.key1 = "value1";
obj.key2 = "value2";

3. 使用自定义构造函数

当我们需要批量创建结构相似的对象时,可以自定义构造函数。

js 复制代码
function Person(name, age) {
  this.name = name;
  this.age = age;
  this.sayHello = function() {
    console.log("你好,我是" + this.name);
  };
}

let p1 = new Person("李四", 30);
let p2 = new Person("王五", 28);

通过构造函数,可以方便地创建多个拥有相同属性和方法的对象实例。

三、构造函数与 new 关键字

构造函数本质上就是一个普通的函数,但约定俗成地首字母大写。当函数被 new 关键字调用时,会发生以下三件事:

  1. 创建一个新的 this 对象。
  2. 执行构造函数中的代码,将属性和方法添加到 this 对象上。
  3. 返回 this 对象。

这就是为什么我们可以通过 new 关键字批量创建对象实例的原因。

四、包装类与自动拆箱

在 JavaScript 中,原始类型(如 number、string、boolean)在需要时会被自动包装成对象,这些包装类分别是 NumberStringBoolean。例如:

js 复制代码
let num = 123;
let objNum = new Number(num);

当我们对字面量调用方法时,JS 会自动将其包装成对象:

js 复制代码
let str = "hello";
console.log(str.length); // 实际上是 new String(str).length

但需要注意的是,包装对象的属性在参与运算时会被自动拆箱成原始类型,且 JS 是弱类型语言,只有在赋值时才会判断类型。如果一个包装对象被判定为原始类型,其上添加的属性会被移除。

js 复制代码
let n = new Number(10);
n.myProp = "test";
console.log(n.myProp); // "test"
let m = n + 1; // 自动拆箱为 10
console.log(m.myProp); // undefined

五、判断数据类型

在实际开发中,我们经常需要判断变量的数据类型。typeof 操作符可以准确判断除 null 以外的所有原始类型:

js 复制代码
console.log(typeof 123); // "number"
console.log(typeof "abc"); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object"(这是 JS 的一个历史遗留问题)
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof function(){}); // "function"

需要注意的是,typeof null 返回的是 "object",这是 JavaScript 早期设计的一个 bug,但一直被保留了下来。

六、案例解析:原始类型与对象的本质区别

在 JavaScript 中,原始类型(如 number、string、boolean)和对象有着本质的区别。通过实际代码案例,我们可以更直观地理解两者的不同。

1. 原始类型不能添加属性和方法

js 复制代码
var num = 123; // 实际上是原始类型 number
num.a = 'aaa';
delete num.a;
console.log(num.a); // 输出 undefined

在上面的代码中,我们尝试给一个 number 类型的变量 num 添加属性 a,但实际上并没有生效。原因在于,原始类型的数据在赋值时不会变成对象,属性的添加和删除操作都不会被保留。

2. 包装类对象可以添加属性

js 复制代码
var num = new Number(123);
num.a = 'aaa';
console.log(num + 1); // 输出 124
console.log(num.a);   // 输出 'aaa'

当我们用 new Number(123) 创建一个包装对象时,这个对象就可以像普通对象一样添加属性和方法。此时,num 是一个对象,而不是原始类型。

3. 字符串的 length 属性

js 复制代码
var str = 'hello'; // 实际上是原始类型 string
console.log(str.length); // 输出 5

虽然 str 是原始类型,但我们依然可以访问 length 属性。这是因为在访问属性时,JavaScript 会临时将原始类型包装成对应的对象(如 String),访问完毕后立即销毁这个临时对象。

4. 数组和字符串的 length 属性操作

js 复制代码
var arr = [1, 2, 3, 4, 5];
arr.length = 2;
console.log(arr); // 输出 [1, 2]

数组的 length 属性是可写的。当我们将 arr.length 设为 2 时,数组会被截断,只保留前两个元素。

js 复制代码
var str = 'abcd';
str.length = 2;
console.log(str); // 输出 'abcd'

而字符串的 length 属性是只读的,尝试修改不会生效,字符串本身也不会被截断。这再次说明了原始类型和对象的不同。 这一行看似是给字符串的 length 属性赋值,但实际上不会生效,原因如下:

  • 在 JavaScript 中,字符串是原始类型,原始类型本身不能添加或修改属性。
  • 当你访问 str.length 时,JavaScript 会临时把 str 包装成一个 String 对象,让你可以读取 length 属性(此时值为 4)。
  • 但是,当你尝试给 str.length 赋值时,JavaScript 依然会临时包装成对象,但这个赋值只会作用在这个临时对象上,不会影响原始字符串本身,而且这个临时对象会立刻被销毁。
  • 所以,str.length = 2; 这行代码什么实际效果都没有,字符串的长度不会被改变,str 依然是 'abcd'

5、知识点总结与面试考点

  1. 原始类型不能添加自定义属性和方法,即使语法上允许写,但不会被保留。
  2. 包装类对象可以添加属性和方法,但在参与运算时会自动拆箱为原始类型。
  3. 字符串的 length 属性是只读的,不能通过赋值改变字符串的长度。
  4. 数组的 length 属性是可写的,可以通过赋值来截断或扩展数组。
  5. 原始类型在访问属性时会被临时包装成对象,访问结束后临时对象被销毁,添加的属性不会保留。

七、总结

JavaScript 对象是 JS 编程的基石。掌握对象的创建方式、构造函数的原理、包装类的自动拆箱机制,以及数据类型的判断方法,是每一个 JS 开发者的必修课。希望本文能帮助你理清 JS 对象的核心知识点,为后续深入学习打下坚实基础。


如果你觉得这篇文章对你有帮助,欢迎点赞、收藏和分享!

相关推荐
J船长几秒前
APK战争 diffoscope
前端
鱼樱前端13 分钟前
重度Cursor用户 最强 Cursor Rules 和 Cursor 配置 mcp 以及最佳实践配置方式
前端
曼陀罗14 分钟前
Path<T> 、 keyof T 什么情况下用合适
前端
锈儿海老师20 分钟前
AST 工具大PK!Biome 的 GritQL 插件 vs. ast-grep,谁是你的菜?
前端·javascript·eslint
飞龙AI22 分钟前
鸿蒙Next实现瀑布流布局
前端
令狐寻欢22 分钟前
JavaScript中 的 Object.defineProperty 和 defineProperties
javascript
快起来别睡了23 分钟前
代理模式:送花风波
前端·javascript·架构
海底火旺25 分钟前
电影应用开发:从代码细节到用户体验优化
前端·css·html
陈随易34 分钟前
Gitea v1.24.0发布,自建github神器
前端·后端·程序员
前端付豪37 分钟前
汇丰银行技术架构揭秘:全球交易稳定背后的“微服务+容灾+零信任安全体系”
前端·后端·架构