javascript中对象的简单了解
|
zhenglin
2026年6月3日 9:5
本文热度 99
|
// 修改已有属性
person.lastName = "Howard Jr.";
// 新增属性
person.nickname = "Curly";
flight.status = "overdue";
4.引用
在 JavaScript 里,对象不是直接存在变量里的,变量存的只是对象的「地址 / 引用」,不是对象本身。
在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方法可以创建以指定对象为原型的新对象
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.原型链的关键特性
anotherStooge.nickname = "Moe";
console.log(anotherStooge.nickname); // "Moe"(自身属性优先)
动态委托:原型链是动态的,给原型新增属性后,所有继承该原型的对象都能实时访问到新属性。
stooge.profession = "actor";
console.log(anotherStooge.profession); // "actor"(原型新增属性实时生效)
删除属性与原型暴露:delete运算符仅删除对象自身的属性,不会影响原型链上的属性。删除自身同名属性后,原型链上的属性会 “浮现” 出来:
delete anotherStooge.nickname;
console.log(anotherStooge.nickname); // "Curly"(原型链属性暴露)
6.反射
反射:程序运行时,动态查看、修改、操作对象自身的属性 / 结构不用提前写死代码,临时读写、判断、遍历对象。
由于原型链的存在,我们要检查属性类别的时候,它无法区分自生属性和继承属性如:
```
typeof flight.number; // "number"
typeof flight.toString; // "function"(继承自Object.prototype)
```
这是我们需要使用**hasOwnProperty()方法**:仅检查对象自身是否存在该属性,不遍历原型链,是区分自身属性和继承属性的关键。
```
flight.hasOwnProperty("number"); // true(自身属性)
flight.hasOwnProperty("constructor"); // false(继承属性)
```
7.枚举
枚举就是遍历对象的属性
使用for..in遍历可遍历对象的所有可枚举属性,但存在两大问题:会遍历原型链上的属性,且遍历顺序不确定。
因此有俩中安全的遍历方法;方法
for (const name in anotherStooge) {
if (anotherStooge.hasOwnProperty(name) && typeof anotherStooge[name] !== 'function') {
console.log(name + ": " + anotherStooge[name]);
}
}
但这种方法无法实现顺序可控
const properties = ["first-name", "middle-name", "profession"];
for (let i = 0; i < properties.length; i++) {
console.log(properties[i] + ": " + anotherStooge[properties[i]]);
}
8.全局变量
js可以很随意的定义可以运用在全局的全局变量,这带来了一个致命的问题,过多的全局变量会削弱程序的灵活性,容易与其他库 / 组件的变量名冲突,导致代码维护困难、调试复杂。这被叫做全局变量污染。
解决全局变量污染的一个经典有效方法就是单全局变量 + 命名空间方案,核心是仅创建一个全局变量,将所有业务对象作为其属性,实现模块化封装:
// 唯一全局变量,作为应用的命名空间
const MYAPP = {};
// 封装业务对象
MYAPP.stooge = {
"first-name": "Joe",
"last-name": "Howard"
};
MYAPP.flight = {
airline: "Oceanic",
number: 815,
departure: { IATA: "SYD", city: "Sydney" }
};
这种方案能有效降低命名冲突风险,让代码结构更清晰,是现代模块化思想的雏形。
阅读原文
该文章在 2026/6/3 9:05:55 编辑过