一、对象的本质与创建方式
1.1 对象的基本概念
JavaScript对象是属性的无序集合,每个属性都是一个键值对:
- 键(Key):字符串或Symbol类型
- 值(Value):任意JavaScript值(原始值、对象或函数)
1.2 创建对象的7种方式
1.2.1 对象字面量
const person = {
name: 'Alice',
age: 28,
greet() {
console.log(`Hello, I'm ${this.name}`);
}
};
1.2.2 构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
const bob = new Person('Bob', 30);
1.2.3 Object.create()
const proto = { greet() { console.log('Hello') } };
const obj = Object.create(proto);
obj.name = 'Alice';
1.2.4 类语法(ES6)
class Person {
constructor(name) {
this.name = name;
}
}
const eve = new Person('Eve');
1.2.5 工厂函数
function createUser(name) {
return {
name,
createdAt: new Date()
};
}
const user = createUser('Charlie');
1.2.6 对象解构重组
const source = { a: 1, b: 2 };
const newObj = { ...source, c: 3 };
1.2.7 动态创建
const dynamicKey = 'id';
const obj = {
[dynamicKey + '_value']: 123,
[Symbol('secret')]: 'hidden'
};
二、对象属性详解
2.1 属性类型分类
| 属性类型 | 示例 | 特点 |
|---|---|---|
| 数据属性 | { a: 1 } | 包含值的普通属性 |
| 访问器属性 | { get a() { return 1 } } | 通过getter/setter定义 |
| 内部属性 | [[Prototype]] | 引擎使用的不可直接访问的属性 |
2.2 属性描述符
const obj = {};
Object.defineProperty(obj, 'readOnlyProp', {
value: 42,
writable: false,
enumerable: true,
configurable: false
});
// 等效的属性描述符默认值
{
value: undefined,
writable: true, // 可修改
enumerable: true, // 可枚举
configurable: true // 可删除和修改特性
}
2.3 属性检测与遍历
2.3.1 检测属性存在性
const obj = { a: 1 };
// 正确方式
'a' in obj; // true
Object.hasOwn(obj, 'a');// true (ES2022)
// 有缺陷的方式
obj.a !== undefined; // 无法区分undefined值
obj.hasOwnProperty('a');// 可能被覆盖
2.3.2 属性遍历方法对比
| 方法 | 获取内容 | 是否遍历原型链 | 是否包含Symbol | 是否包含不可枚举 |
|---|---|---|---|---|
for...in | 可枚举的字符串键 | 是 | 否 | 否 |
Object.keys() | 自身可枚举的字符串键 | 否 | 否 | 否 |
Object.getOwnPropertyNames() | 自身所有字符串键 | 否 | 否 | 是 |
Object.getOwnPropertySymbols() | 自身所有Symbol键 | 否 | 是 | 是 |
Reflect.ownKeys() | 自身所有键 | 否 | 是 | 是 |
三、对象原型与继承
3.1 原型链机制
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(`${this.name} makes a noise`);
};
function Dog(name) {
Animal.call(this, name);
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
const d = new Dog('Rex');
d.speak(); // Rex makes a noise
3.2 现代继承方式(ES6类)
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise`);
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
speak() {
console.log(`${this.name} barks`);
}
}
const d = new Dog('Rex');
d.speak(); // Rex barks
3.3 原型相关方法
// 获取原型
Object.getPrototypeOf(obj);
Reflect.getPrototypeOf(obj);
// 设置原型
Object.setPrototypeOf(obj, proto); // 性能差
const newObj = Object.create(proto); // 推荐方式
四、对象的高级特性
4.1 不可变对象
4.1.1 浅层不可变
const frozen = Object.freeze({ a: 1 });
frozen.a = 2; // 静默失败(严格模式报错)
const sealed = Object.seal({ a: 1 });
sealed.a = 2; // 允许修改值
sealed.b = 3; // 禁止添加属性
const nonExtensible = Object.preventExtensions({ a: 1 });
nonExtensible.a = 2; // 允许
nonExtensible.b = 3; // 禁止
4.1.2 深层不可变
function deepFreeze(obj) {
Object.freeze(obj);
Object.getOwnPropertyNames(obj).forEach(prop => {
if (obj[prop] !== null &&
typeof obj[prop] === 'object' &&
!Object.isFrozen(obj[prop])) {
deepFreeze(obj[prop]);
}
});
return obj;
}
4.2 对象代理(Proxy)
const handler = {
get(target, prop) {
return prop in target ? target[prop] : 37;
},
set(target, prop, value) {
if (prop === 'age' && !Number.isInteger(value)) {
throw new TypeError('Age must be an integer');
}
target[prop] = value;
return true;
}
};
const p = new Proxy({}, handler);
p.age = 12;
console.log(p.age); // 12
console.log(p.name); // 37
4.3 反射API(Reflect)
const obj = { a: 1 };
// 代替Object方法
Reflect.set(obj, 'b', 2);
Reflect.has(obj, 'a'); // true
// 与Proxy配合
const proxy = new Proxy(obj, {
get(target, prop) {
console.log(`Getting ${prop}`);
return Reflect.get(target, prop);
}
});
五、对象操作的最佳实践
5.1 安全的对象扩展
// 不安全的扩展(可能覆盖已有方法)
Object.prototype.customMethod = function() {};
// 安全的方式
if (!Object.prototype.customMethod) {
Object.defineProperty(Object.prototype, 'customMethod', {
value: function() { /*...*/ },
enumerable: false // 不污染for...in
});
}
5.2 深拷贝实现
function deepClone(obj, cache = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (cache.has(obj)) return cache.get(obj);
const clone = Array.isArray(obj) ? [] : {};
cache.set(obj, clone);
Object.getOwnPropertyNames(obj).concat(
Object.getOwnPropertySymbols(obj)
).forEach(prop => {
clone[prop] = deepClone(obj[prop], cache);
});
return clone;
}
5.3 属性枚举顺序
ES6规范定义了对象属性的枚举顺序:
- 所有数字键按升序排列
- 所有字符串键按添加顺序排列
- 所有Symbol键按添加顺序排列
const obj = {
'2': 'two',
'1': 'one',
b: 'b',
a: 'a',
[Symbol('s2')]: 'sym2',
[Symbol('s1')]: 'sym1'
};
Reflect.ownKeys(obj); // ['1', '2', 'b', 'a', Symbol(s2), Symbol(s1)]
六、特殊对象类型
6.1 内置对象
| 类型 | 用途 | 示例 |
|---|---|---|
| Array | 有序数据集合 | [1, 2, 3] |
| Date | 日期时间处理 | new Date() |
| RegExp | 正则表达式 | /\d+/g |
| Map/Set | 键值对/值集合 | new Map([[k, v]]) |
| WeakMap/WeakSet | 弱引用集合 | new WeakMap() |
| ArrayBuffer | 二进制数据 | new ArrayBuffer(8) |
| Promise | 异步操作 | new Promise(...) |
6.2 宿主对象
由JavaScript运行环境提供的对象:
- 浏览器:
window,document,XMLHttpRequest - Node.js:
process,require,module
七、对象性能优化
7.1 对象结构优化
// 不佳实践:频繁改变对象结构
function process(obj) {
obj.newProp = computeValue(); // 隐藏类改变
// ...
}
// 优化:初始化完整结构
function createObject() {
return {
prop1: null,
prop2: null, // 预先分配
method() { /*...*/ }
};
}
7.2 对象池技术
class ObjectPool {
constructor(createFn) {
this.createFn = createFn;
this.pool = [];
}
acquire() {
return this.pool.length ? this.pool.pop() : this.createFn();
}
release(obj) {
// 重置对象状态
this.pool.push(obj);
}
}
// 使用
const pool = new ObjectPool(() => ({ x: 0, y: 0 }));
const obj = pool.acquire();
// 使用后...
pool.release(obj);
八、现代JavaScript对象特性
8.1 对象解构(ES6)
// 基本解构
const { name, age } = user;
// 重命名
const { name: userName } = user;
// 默认值
const { permissions = 'read' } = user;
// 嵌套解构
const { address: { city } } = user;
// 函数参数解构
function greet({ name, age }) {
return `Hello ${name}, you're ${age}`;
}
8.2 对象扩展运算符(ES2018)
// 浅拷贝
const copy = { ...original };
// 合并对象
const merged = { ...obj1, ...obj2 };
// 覆盖属性
const updated = { ...user, name: 'New Name' };
// 条件添加属性
const config = {
baseUrl: '/api',
...(devMode && { debug: true })
};
8.3 可选链(ES2020)
// 安全访问嵌套属性
const street = user?.address?.street;
// 配合空值合并
const name = user?.name ?? 'Anonymous';
// 方法调用
user.sayHello?.();
// 数组访问
arr?.[0];
九、对象与类型系统
9.1 TypeScript对象类型
// 接口定义
interface User {
id: number;
name: string;
email?: string; // 可选属性
readonly createdAt: Date; // 只读属性
[key: string]: any; // 索引签名
}
// 类型别名
type Point = {
x: number;
y: number;
distance(): number;
};
// 泛型对象
type Response<T> = {
data: T;
status: number;
};
9.2 运行时类型检查
// 类型保护
function isUser(obj) {
return obj && typeof obj === 'object' &&
'id' in obj && 'name' in obj;
}
// 结构化类型检查
function validateShape(obj, shape) {
return Object.keys(shape).every(key =>
typeof obj[key] === shape[key]
);
}