对象是JavaScript中最基本的引用类型,是属性的集合。
// 对象是键值对的集合
let user = {
name: "东巴文",
age: 1,
isActive: true
};
console.log(typeof user); // "object"
| 特点 | 说明 | 东巴文评价 |
|---|---|---|
| 动态性 | 可以随时添加/删除属性 | ✅ 灵活 |
| 引用传递 | 赋值时传递引用地址 | ⚠️ 注意共享问题 |
| 属性类型 | 支持数据属性和访问器属性 | ✅ 功能强大 |
| 键的类型 | 字符串或Symbol | - |
// 最常用的创建方式
let user = {
name: "东巴文",
age: 1,
greet: function() {
return `你好,我是${this.name}`;
}
};
// ES6增强写法
let name = "东巴文";
let age = 1;
let user2 = {
name, // 等同于 name: name
age, // 等同于 age: age
greet() { // 方法定义简写
return `你好,我是${this.name}`;
}
};
let user = new Object();
user.name = "东巴文";
user.age = 1;
// 不推荐,更繁琐
// 创建一个没有原型的对象
let obj = Object.create(null);
// 创建一个继承原型的对象
let person = {
greet() {
return "你好";
}
};
let user = Object.create(person);
user.name = "东巴文";
console.log(user.greet()); // "你好"
function User(name, age) {
this.name = name;
this.age = age;
this.greet = function() {
return `你好,我是${this.name}`;
};
}
let user = new User("东巴文", 1);
console.log(user.name); // "东巴文"
function createUser(name, age) {
return {
name,
age,
greet() {
return `你好,我是${this.name}`;
}
};
}
let user = createUser("东巴文", 1);
console.log(user.greet()); // "你好,我是东巴文"
let user = {
name: "东巴文",
age: 1
};
console.log(user.name); // "东巴文"
user.age = 2; // 修改属性
user.email = "test@example.com"; // 添加属性
let user = {
name: "东巴文",
"full name": "东巴文学习平台"
};
console.log(user["name"]); // "东巴文"
console.log(user["full name"]); // "东巴文学习平台"
// 动态属性名
let key = "name";
console.log(user[key]); // "东巴文"
// 计算属性名(ES6)
let prop = "age";
let obj = {
[prop]: 1,
["na" + "me"]: "东巴文"
};
console.log(obj.age); // 1
console.log(obj.name); // "东巴文"
| 特性 | 点表示法 | 方括号表示法 | 东巴文建议 |
|---|---|---|---|
| 标识符规则 | 必须是有效标识符 | 可以是任意字符串 | 点法更简洁 |
| 空格和特殊字符 | 不支持 | 支持 | 方括号更灵活 |
| 动态属性名 | 不支持 | 支持 | 方括号必需 |
| 数字键 | 不支持 | 支持 | 方括号必需 |
let obj = {
"1": "数字键",
"my-key": "连字符键"
};
// console.log(obj.1); // SyntaxError
console.log(obj["1"]); // "数字键"
// console.log(obj.my-key); // 被解析为减法
console.log(obj["my-key"]); // "连字符键"
每个属性都有描述符,定义属性的行为。
let user = {
name: "东巴文"
};
let descriptor = Object.getOwnPropertyDescriptor(user, "name");
console.log(descriptor);
// {
// value: "东巴文",
// writable: true,
// enumerable: true,
// configurable: true
// }
| 属性 | 默认值 | 说明 | 东巴文解释 |
|---|---|---|---|
| value | undefined | 属性值 | 存储的数据 |
| writable | false | 是否可修改 | 控制写入 |
| enumerable | false | 是否可枚举 | 控制遍历 |
| configurable | false | 是否可配置 | 控制删除和修改描述符 |
let user = {};
Object.defineProperty(user, "name", {
value: "东巴文",
writable: false, // 不可修改
enumerable: true, // 可枚举
configurable: false // 不可删除
});
console.log(user.name); // "东巴文"
user.name = "新名字"; // 静默失败(严格模式报错)
console.log(user.name); // "东巴文"
// delete user.name; // 删除失败
let user = {
firstName: "东",
lastName: "巴文"
};
Object.defineProperty(user, "fullName", {
get() {
return `${this.firstName}${this.lastName}`;
},
set(value) {
[this.firstName, this.lastName] = value.split("");
},
enumerable: true,
configurable: true
});
console.log(user.fullName); // "东巴文"
user.fullName = "新名字";
console.log(user.firstName); // "新"
console.log(user.lastName); // "名字"
let user = {};
Object.defineProperties(user, {
name: {
value: "东巴文",
writable: true
},
age: {
value: 1,
writable: false
}
});
let user = {
name: "东巴文",
age: 1,
email: "test@example.com"
};
console.log(Object.keys(user)); // ["name", "age", "email"]
console.log(Object.values(user)); // ["东巴文", 1, "test@example.com"]
console.log(Object.entries(user));
// [["name", "东巴文"], ["age", 1], ["email", "test@example.com"]]
// 遍历键值对
for (let [key, value] of Object.entries(user)) {
console.log(`${key}: ${value}`);
}
let target = { a: 1 };
let source = { b: 2, c: 3 };
let result = Object.assign(target, source);
console.log(result); // { a: 1, b: 2, c: 3 }
console.log(target); // { a: 1, b: 2, c: 3 }(target被修改)
// 合并多个对象
let merged = Object.assign({}, { a: 1 }, { b: 2 }, { c: 3 });
console.log(merged); // { a: 1, b: 2, c: 3 }
let user = {
name: "东巴文",
age: 1
};
Object.freeze(user);
user.name = "新名字"; // 静默失败
user.email = "test@example.com"; // 静默失败
delete user.age; // 静默失败
console.log(user); // { name: "东巴文", age: 1 }
// 检查是否被冻结
console.log(Object.isFrozen(user)); // true
let user = {
name: "东巴文",
age: 1
};
Object.seal(user);
user.name = "新名字"; // 可以修改
// delete user.age; // 不能删除
// user.email = ""; // 不能添加
console.log(user); // { name: "新名字", age: 1 }
console.log(Object.isSealed(user)); // true
| 操作 | freeze | seal | 东巴文说明 |
|---|---|---|---|
| 修改属性 | ❌ | ✅ | freeze完全冻结 |
| 添加属性 | ❌ | ❌ | 都不能添加 |
| 删除属性 | ❌ | ❌ | 都不能删除 |
| 修改描述符 | ❌ | ❌ | 都不能修改 |
// 方法1:Object.assign()
let obj1 = { a: 1, b: { c: 2 } };
let copy1 = Object.assign({}, obj1);
// 方法2:展开运算符
let copy2 = { ...obj1 };
// 方法3:JSON方法
let copy3 = JSON.parse(JSON.stringify(obj1));
// 浅拷贝的问题
obj1.b.c = 100;
console.log(copy1.b.c); // 100(受影响,因为b是引用类型)
// 方法1:JSON方法(有局限性)
let obj = {
name: "东巴文",
date: new Date(),
func: function() {}
};
let copy = JSON.parse(JSON.stringify(obj));
console.log(copy.name); // "东巴文"
console.log(copy.date); // 字符串,不是Date对象
console.log(copy.func); // undefined(函数丢失)
// 方法2:递归实现
function deepClone(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (hash.has(obj)) {
return hash.get(obj);
}
let clone = Array.isArray(obj) ? [] : {};
hash.set(obj, clone);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], hash);
}
}
return clone;
}
// 方法3:structuredClone(现代浏览器支持)
let obj2 = { a: 1, b: { c: 2 } };
let copy2 = structuredClone(obj2);
| 方案 | 优点 | 缺点 | 东巴文建议 |
|---|---|---|---|
| JSON方法 | 简单 | 不支持函数、Date等 | 简单场景 |
| 递归实现 | 完整支持 | 需要自己实现 | 学习理解 |
| structuredClone | 原生支持 | 兼容性问题 | 现代项目 |
| lodash.cloneDeep | 功能完整 | 需要引入库 | 生产环境 |
let obj1 = { name: "东巴文" };
let obj2 = { name: "东巴文" };
let obj3 = obj1;
console.log(obj1 === obj2); // false(不同引用)
console.log(obj1 === obj3); // true(同一引用)
function shallowEqual(obj1, obj2) {
if (obj1 === obj2) return true;
if (typeof obj1 !== "object" || obj1 === null ||
typeof obj2 !== "object" || obj2 === null) {
return false;
}
let keys1 = Object.keys(obj1);
let keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) return false;
for (let key of keys1) {
if (obj1[key] !== obj2[key]) {
return false;
}
}
return true;
}
let a = { name: "东巴文", age: 1 };
let b = { name: "东巴文", age: 1 };
console.log(shallowEqual(a, b)); // true
function deepEqual(obj1, obj2) {
if (obj1 === obj2) return true;
if (typeof obj1 !== "object" || obj1 === null ||
typeof obj2 !== "object" || obj2 === null) {
return false;
}
let keys1 = Object.keys(obj1);
let keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) return false;
for (let key of keys1) {
if (!deepEqual(obj1[key], obj2[key])) {
return false;
}
}
return true;
}
let a = { name: "东巴文", info: { age: 1 } };
let b = { name: "东巴文", info: { age: 1 } };
console.log(deepEqual(a, b)); // true
掌握了引用类型后,让我们继续学习:
东巴文(db-w.cn) - 让编程学习更简单
📦 东巴文寄语:对象是JavaScript的核心,理解对象的创建、属性操作和拷贝机制,是掌握JavaScript的关键。在 db-w.cn,我们帮你深入理解每一个概念!