JS对象入门|从创建到原理,一篇吃透核心知识点

前言

在JavaScript的世界里,有一句广为人知的话------"万物皆对象" 。无论是我们日常使用的字符串、数字,还是自定义的函数、数组,本质上都和"对象"有着千丝万缕的联系。但很多新手在学习对象时,总会被"构造函数""new关键字""包装类"这些概念绕晕,今天就结合具体代码实例,用通俗易懂的语言,把JS对象的核心知识点讲明白、讲透彻。

一、先搞懂:什么是对象?

对象(Object)是JS中最核心的数据类型之一,它就像一个"收纳盒",可以存放多个不同类型的数据(我们称之为"属性")和可执行的操作(我们称之为"方法")。比如一个"人"可以有姓名、年龄(属性),可以吃饭、睡觉(方法);一辆车可以有颜色、尺寸(属性),可以行驶、刹车(方法),对象就是用来描述这种"具有多种特征的事物"的。

在JS中,数据类型分为两大类,这也是理解对象的基础:

  • 原始类型:简单数据类型,无法拥有属性和方法,包括:string(字符串)、number(数字)、bool(布尔值)、undefined(未定义)、null(空值)、Symbol(唯一值)、bigInt(大整数)。

  • 引用类型:复杂数据类型,本质上都是对象,能拥有属性和方法,包括:函数(function)、数组(array)、普通对象(object)等。

这里要注意一个易错点:原始类型一定无法添加属性和方法,属性和方法是对象独有的,后面我们会通过"包装类"详细解释这一点

二、3种创建对象的方式

日常开发中,我们创建对象的方式主要有3种,各自有不同的使用场景,结合代码实例一看就懂!

1. 对象字面量 {}|最简洁常用

这是最直观、最常用的创建方式,用大括号 {} 包裹属性和值,属性和值之间用冒号 : 分隔,多个属性之间用逗号 , 分隔,适合创建单个、简单的对象。

javascript 复制代码
// 实例1:创建一个"人物"对象
const person = {
  name: '米奇',  // 属性:姓名,值为字符串
  age: 18,       // 属性:年龄,值为数字
  sayHi: function() {  // 方法:打招呼
    console.log('你好呀,我是米奇~');
  }
}
console.log(person); // 输出:{ name: '米奇', age: 18, sayHi: [Function: sayHi] }
person.sayHi(); // 调用方法,输出:你好呀,我是米奇~

// 实例2:创建一个空对象,后续添加属性
const obj = {};
obj.name = '米妮';
obj.age = 17;
console.log(obj); // 输出:{ name: '米妮', age: 17 }

2. new Object()|构造函数创建 🛠️

这是通过JS内置的构造函数 Object() 创建对象,本质和对象字面量一样,只是写法更繁琐,适合动态添加属性的场景。

javascript 复制代码
// 实例:用new Object()创建对象,并动态添加属性
const obj = new Object(); // 先创建一个空对象
obj.name = '米妮'; // 给对象添加name属性
const abc = 'age'; // 用变量作为属性名
obj[abc] = 18; // 动态添加age属性(括号语法适合属性名是变量的场景)
console.log(obj); // 输出:{ name: '米妮', age: 18 }

//  delete关键字:删除对象的属性
delete obj[abc]; // 删除age属性
console.log(obj); // 输出:{ name: '米妮' }

这里补充一个小知识点:delete 关键字只能删除对象的属性,不能删除变量;而且删除后,再访问该属性会返回 undefined

3. new 调用自定义构造函数|批量创建对象

当我们需要批量创建多个结构相同的对象(比如多个用户、多辆车)时,用前面两种方式就太繁琐了------这时候,自定义构造函数就派上用场了!

先明确一个概念:当一个函数被 new 关键字调用时,这个函数就被称为"构造函数"。构造函数的命名规范是:首字母大写(区分普通函数),目的是为了批量生成具有相同属性结构的对象。

javascript 复制代码
// 实例1:自定义构造函数Person,批量创建人物对象
function Animal(name, age, role) {
  // this指向当前创建的对象,给对象添加属性
  this.name = name;
  this.age = age;
  this.role = role;
  // 也可以添加方法
  this.introduce = function() {
    console.log(`我是${this.name},今年${this.age}岁,我的角色是${this.role}`);
  }
}

// new调用构造函数,创建2个实例对象
const p1 = new Animal('米奇', 8, 'animal');
const p2 = new Animal('跳跳虎', 9, 'tigger');

console.log(p1); // 输出:Animal { name: '米奇', age: 8, role: 'animal', introduce: [Function (anonymous)] }
console.log(p2); // 输出:Animal { name: '跳跳虎', age: 9, role: 'tigger', introduce: [Function (anonymous)] }
p1.introduce(); // 调用方法,输出:我是米奇,今年8岁,我的角色是animal

// 实例2:自定义构造函数Car,批量创建汽车对象
function Car(color) {
  // 固定属性(所有汽车都一样)
  this.name = 'su7';
  this.height = '1400';
  this.lang = '4800';
  this.weight = '1500';
  // 动态属性(不同汽车可以不一样)
  this.color = color;
}

// 批量创建2辆汽车
const car1 = new Car('purple'); // 紫色的su7
const car2 = new Car('pink');   // 粉色的su7
const car3 =  Car('pink');   // 粉色的su7
console.log(car1); // 输出:Car { name: 'su7', height: '1400', lang: '4800', weight: '1500', color: 'purple' } 

易错点提醒:构造函数必须用 new 调用!如果忘记写 new,函数会变成普通函数,this 会指向全局(浏览器中是window,Node环境中是global),此时返回值是undefined。

错误示例:忘记new,调用Car函数 const car3 = Car(black); console.log(car3); // 输出:undefined(因为普通函数没有return值)

三、重点突破:new关键字到底干了什么? 🔍

很多新手都会疑惑:为什么用 new 调用构造函数,就能创建出对象?其实 new 关键字背后只做了3件事,简单好记,结合代码拆解:

  1. 创建一个空的this对象 :相当于执行 const _this = {},这个空对象就是未来要返回的实例对象。

  2. 执行构造函数中的代码,给this对象添加属性 :把构造函数中 this.xxx 的内容,都添加到第一步创建的空对象上。

  3. 返回这个this对象:不需要我们手动写return,new会自动把添加好属性的this对象返回,赋值给变量。

我们可以用一段"模拟new操作"的代码,更直观地理解这个过程:

javascript 复制代码
// 模拟new关键字的作用,手动实现构造函数的逻辑
function car() {
  // 1. 创建一个空对象(对应new的第一步)
  const _this = {};
  // 2. 给空对象添加属性(对应new的第二步)
  _this.name = 'su7';
  _this.color = 'green';
  // 3. 返回这个对象(对应new的第三步)
  return _this;
}

// 调用函数,得到实例对象(相当于new person())
const obj = car();
console.log(obj); // 输出:{ name: 'su7', color: 'green' }

new的核心就是"自动帮我们创建对象、添加属性、返回对象",省去了我们手动写这些重复代码的麻烦~

四、易错点:包装类|为什么原始类型不能加属性? 🧐

前面我们说过"原始类型一定无法添加属性和方法",但很多新手会写出这样的代码,然后疑惑为什么结果不符合预期:

javascript 复制代码
// 看似给数字添加属性,实则无效
var num = 123;
num.a = 'aaa'; // 尝试给原始类型num添加属性a
delete num.a;  // 尝试删除属性a
console.log(num.a); // 输出:undefined

// 看似给字符串添加属性,实则无效
var str = 'hello';
str.len = 2; // 尝试给原始类型str添加属性len
console.log(str.len); // 输出:undefined

这就涉及到JS中的"包装类"(Wrapper Class)概念,其实V8引擎在背后做了"隐式操作",我们拆解一下过程:

什么是包装类?

包装类是JS内置的、对应原始类型的构造函数,包括:String()Number()Boolean()。它们的作用是:当我们对原始类型进行"属性操作"时,引擎会自动把原始类型转换成对应的包装类实例对象,操作完成后,再自动销毁这个实例对象------这就是"自动装箱"和"自动拆箱"。

拆解上面的错误示例:

javascript 复制代码
var num = 123; // 原始类型(number)
num.a = 'aaa'; // 引擎隐式操作:
// 1. 自动装箱:new Number(123).a = 'aaa'(创建包装类实例,添加属性)
// 2. 操作完成后,自动销毁这个实例对象
delete num.a;  // 同样隐式创建实例,删除属性后销毁
console.log(num.a); // 再次隐式创建新的实例,新实例没有a属性,所以返回undefined

核心总结:

  • 当我们定义一个原始类型字面量(如var str ='hello'),V8引擎默认执行的还是 new String('hello')(创建包装类实例),但会自动拆箱成原始类型。

  • 包装类的实例对象,参与运算时会自动拆箱成原始类型(比如123 + new Number(456) = 579)。

  • JS是弱类型语言,只有在赋值语句执行时,才会判断值的类型;当值被判定为原始类型时,就会自动将包装对象上添加的属性移除------所以我们给原始类型加属性,永远无效。

五、总结|核心知识点梳理 📝

看完上面的内容,相信你已经掌握了JS对象的核心知识点,我们用一张表格快速梳理,方便记忆:

知识点 核心内容 关键提醒
对象本质 存放属性和方法的"收纳盒",引用类型的核心 万物皆对象,但原始类型不是对象
创建方式 1. 对象字面量 {};2. new Object();3. new 自定义构造函数 批量创建用自定义构造函数
new的作用 1. 创建this空对象;2. 执行构造函数添加属性;3. 返回this对象 构造函数必须用new调用
包装类 原始类型属性操作时的隐式实例,操作后自动销毁 原始类型无法添加属性和方法

🐾 最后提醒:JS对象是前端开发的基础,后续的原型、原型链、继承等知识点,都建立在对象的基础上。祝大家学习顺利,写出更优雅的JS代码!

相关推荐
麦秋2 小时前
前端静态页面自动生成(Figma MCP + VS code + Github copilot)
前端·vue.js
DongHao2 小时前
我不想一开始就把 Axios 封装的太完美
前端·http·axios
六元七角八分2 小时前
学习笔记一《JavaScript基础语法》
javascript·笔记·学习
有一个好名字3 小时前
claude code安装
linux·运维·前端
BIBABULALA3 小时前
Mini Virtual Machine — 可视化虚拟机模拟器(91行)
前端·css·css3
筱璦3 小时前
期货软件开发「启动加载页 / 初始化窗口」
前端·c#·策略模式·期货
只与明月听3 小时前
RAG深入学习之Emabedding
前端·python·面试
We་ct3 小时前
React Scheduler & Lane 详解
前端·react.js·前端框架·reactjs·个人开发·任务调度·优先
小道士写程序3 小时前
Babylon.js WebGPU Ocean Demo — 完整踩坑记录
开发语言·javascript·ecmascript