javascript中对象的简单了解

对象

JavaScript 中,除数字(number)、字符串(string)、布尔值(boolen)、null和undefined这五种基本语言类型外,所有值都是对象(Object) ,包括数组、函数、正则表达式等,对象也是对象对象是属性的容器 ,其中的每个属性都有名字和值。对象本质是可变的键控集合(keyed collections) ,具备三大核心特性:

  • 无类别(class-free) :JS 对象不依赖类定义,对属性名和值没有强制约束,可动态新增 / 修改属性,天生适合收集和管理数据,也能通过嵌套轻松实现树形或图形结构。
  • 类对象特性:数字、字符串、布尔值是 "类对象",拥有方法但不可变;而普通对象是可变的,修改属性会直接影响原对象。
  • 引用传递:对象按引用传递而非值传递,变量存储的是对象的内存地址,多个变量指向同一对象时,修改其中一个会同步影响其他变量。

1.对象字面量

对象字面量是 JS 中创建对象最常用的方式,语法简洁直观:

js 复制代码
// 空对象
 const emptyObj = {};
 // 简单对象
 const person = { 
 "first-name": "Jerome",// 含特殊字符需加引号
 lastName: "Howard" // 合法标识符可省略引号 
 };
// 嵌套对象(支持多层级数据结构) 
const flight = {
 airline: "Oceanic",
 number: 815,
 departure: { 
  IATA: "SYD",
  time: "2004-09-22 14:55", 
  city: "Sydney"
 } 
};

属性名可以是任意字符串(包括空字符串),值可以是除undefined外的任意值,支持对象嵌套实现复杂数据结构。

2.检索

对象的检索是要检索对象中包含的值,有俩种写法可以表示进行对象的检索。第一种是在[]后缀中括住一个字符串表达式的方法。第二种是.表示法。两种方法的区别:

  • .语法:简洁易读,仅适用于合法标识符属性(不含特殊字符、关键字)。

  • []语法:支持字符串表达式、变量或特殊字符属性名,更灵活但可读性稍差。

js 复制代码
// 合法属性名用点语法 
flight.departure.IATA; // "SYD" 
// 特殊字符属性名用方括号语法 
person["first-name"]; // "Jerome"

访问不存在的成员元素的值undefined

可通过||设置默认值。

js 复制代码
const middleName = person["middle-name"] || "(none)";

尝试检索一个undefined值会导致TypeError异常。 可通过&&避免访问undefined上的属性导致错误:

js 复制代码
flight.equipment && flight.equipment.model;//undefined

3.更新

更新语句可以动态的修改或新增对象属性

  • 属性已存在:赋值会替换原有值。
  • 属性不存在:赋值会给对象新增该属性。
js 复制代码
// 修改已有属性 
person.lastName = "Howard Jr."; 
// 新增属性 
person.nickname = "Curly";
flight.status = "overdue";

4.引用

在 JavaScript 里,对象不是直接存在变量里的,变量存的只是对象的「地址 / 引用」,不是对象本身。

在js中,对象,数组,函数都是引用类型,他们的存储方式是存引用,赋值是赋值地址 就像:

  • 变量 = 门牌号
  • 对象 = 房子本身
  • 引用 = 指向房子的地址

有点类似与指针的感觉,都是指向地址,如果多个变量指向同一个对象时,修改一个,全都会边。

举个例子:

js 复制代码
// 创建一个真实的对象(房子)
let obj1 = { name: "小明" };
// 把 obj1 的「引用」赋值给 obj2(复制门牌号)
let obj2 = obj1; 
// 修改 obj2,等于修改同一个对象
obj2.name = "小红";
console.log(obj1.name); // 小红 

5.原型

原型简单点来说就是每个对象天生自带一个隐藏祖宗对象,这个祖宗就是原型

原型有点类似与java中的继承,但他俩本质不同,用途类似,都是为了代码的复用+共享属性方法

用一张简单的表格来简单的说明js中原型和java中的继承的区别:

特点 Java 类继承 JavaScript 原型继承
基础单位 类(class) 对象(object)
工作方式 复制继承 委托 / 查找
子改父 不能影响父 不能影响原型
父改子 不能动态改 原型一变,所有子立刻生效
灵活度 低(静态) 高(动态)

由此可见,js原型是java继承的动态灵活版,这是js的语法优势。

接下来介绍一些原型的知识:

1. 原型链的核心概念

每个对象都连接到一个原型对象,可从中继承属性。所有通过对象字面量创建的对象,默认原型是Object.prototype,这也是为什么普通对象能调用toString()hasOwnProperty()等方法。 原型链的工作规则可总结为:读属性时向上找,写属性时不碰原型

2.Object.beget:创建原型继承的简化实现

所有通过对象字面量创建的对象,默认原型是Object.prototype,但通过Object.beget方法可以创建以指定对象为原型的新对象

js 复制代码
if (typeof Object.beget !== 'function') { 
Object.beget = function (o) 
{ var F = function () {};
F.prototype = o;
return new F(); };
} 
// 使用示例 
const stooge = { nickname: "Curly" }; 
const anotherStooge = Object.beget(stooge);

此时anotherStooge的原型链为:anotherStooge → stooge → Object.prototype → null

3.原型链的关键特性

  • 属性遮蔽:当对象自身存在与原型链同名的属性时,会优先访问自身属性,遮蔽原型链上的属性。

    ini 复制代码
    anotherStooge.nickname = "Moe";
    console.log(anotherStooge.nickname); // "Moe"(自身属性优先)
  • 动态委托:原型链是动态的,给原型新增属性后,所有继承该原型的对象都能实时访问到新属性。

    ini 复制代码
    stooge.profession = "actor";
    console.log(anotherStooge.profession); // "actor"(原型新增属性实时生效)
  • 删除属性与原型暴露delete运算符仅删除对象自身的属性,不会影响原型链上的属性。删除自身同名属性后,原型链上的属性会 "浮现" 出来:

    arduino 复制代码
    delete anotherStooge.nickname;
    console.log(anotherStooge.nickname); // "Curly"(原型链属性暴露)

6.反射

反射:程序运行时,动态查看、修改、操作对象自身的属性 / 结构不用提前写死代码,临时读写、判断、遍历对象。

由于原型链的存在,我们要检查属性类别的时候,它无法区分自生属性和继承属性如:

vbnet 复制代码
```
typeof flight.number; // "number"
typeof flight.toString; // "function"(继承自Object.prototype)
```

这是我们需要使用**hasOwnProperty()方法**:仅检查对象自身是否存在该属性,不遍历原型链,是区分自身属性和继承属性的关键。

arduino 复制代码
```
flight.hasOwnProperty("number"); // true(自身属性)
flight.hasOwnProperty("constructor"); // false(继承属性)
```

7.枚举

枚举就是遍历对象的属性

使用for..in 遍历可遍历对象的所有可枚举属性,但存在两大问题:会遍历原型链上的属性 ,且遍历顺序不确定

因此有俩中安全的遍历方法;方法

  • 结合hasOwnProperty()过滤:同时过滤原型链属性和函数属性,确保仅遍历对象自身的非函数属性。

    javascript 复制代码
    for (const name in anotherStooge) {
      if (anotherStooge.hasOwnProperty(name) && typeof anotherStooge[name] !== 'function') {
        console.log(name + ": " + anotherStooge[name]);
      }
    }

但这种方法无法实现顺序可控

  • 数组 + 普通for循环:将属性名存入数组,通过索引遍历,顺序可控且无原型链干扰,适合对遍历顺序有要求的场景。

    ini 复制代码
    const properties = ["first-name", "middle-name", "profession"];
    for (let i = 0; i < properties.length; i++) {
      console.log(properties[i] + ": " + anotherStooge[properties[i]]);
    }

8.全局变量

js可以很随意的定义可以运用在全局的全局变量,这带来了一个致命的问题,过多的全局变量会削弱程序的灵活性,容易与其他库 / 组件的变量名冲突,导致代码维护困难、调试复杂。这被叫做全局变量污染。

解决全局变量污染的一个经典有效方法就是单全局变量 + 命名空间方案,核心是仅创建一个全局变量,将所有业务对象作为其属性,实现模块化封装:

arduino 复制代码
// 唯一全局变量,作为应用的命名空间
const MYAPP = {};

// 封装业务对象
MYAPP.stooge = {
  "first-name": "Joe",
  "last-name": "Howard"
};

MYAPP.flight = {
  airline: "Oceanic",
  number: 815,
  departure: { IATA: "SYD", city: "Sydney" }
};

这种方案能有效降低命名冲突风险,让代码结构更清晰,是现代模块化思想的雏形。

相关推荐
candyTong2 小时前
Claude Code 的 Skill 动态发现机制
javascript
小KK_2 小时前
写给前端小白:我终于搞懂了JS原型和原型链
前端·javascript
HjhIron3 小时前
学习并且总结JavaScript对象
javascript
拾年2753 小时前
520刚过,今天来教你怎么"驾驭"别人的对象
前端·javascript
Darling噜啦啦5 小时前
深入理解 JavaScript 函数:从《语言精粹》第四章看函数的精髓
javascript
宋浮檀s6 小时前
DVWA通关教程2
运维·服务器·前端·javascript
皮卡祺q6 小时前
【算法-0】背包问题(三维+二维)
java·javascript·算法
whuhewei7 小时前
手写Promise
开发语言·javascript·ecmascript
川冰ICE7 小时前
JavaScript入门⑤|数组方法全攻略,map/filter/reduce三剑客
开发语言·javascript·ecmascript