JavaScript 中的对象是一种无序的数据集合,由键值对组成,是这门语言中最为重要的数据类型之一。以下是对 JavaScript 对象的全面总结:
一、对象基础
1. 对象的定义与创建
对象可以通过多种方式创建:
javascript
// 1. 对象字面量(最常用)
const person = {
name: "张三",
age: 30,
isStudent: false,
hobbies: ["阅读", "游泳", "编程"],
address: {
city: "北京",
zipCode: "100000"
},
// 方法
greet: function() {
return `你好,我是${this.name},今年${this.age}岁。`;
}
};
// 2. 使用构造函数
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
this.getDetails = function() {
return `${this.year} ${this.make} ${this.model}`;
};
}
const myCar = new Car("Toyota", "Corolla", 2020);
// 3. Object.create() 方法(继承指定原型对象)
const animal = {
type: "动物",
sound: function() {
return "发出声音";
}
};
const dog = Object.create(animal);
dog.breed = "金毛";
dog.bark = function() {
return "汪汪汪!";
};
// 4. 类(ES6 引入的语法糖)
class Rectangle {
constructor(width, height) {
this.width = width;
this.height = height;
}
area() {
return this.width * this.height;
}
}
const rect = new Rectangle(5, 10);
2. 访问和修改对象属性
javascript
// 点表示法
console.log(person.name); // 张三
person.age = 31;
// 方括号表示法(动态访问)
const propertyName = "name";
console.log(person[propertyName]); // 张三
// 计算属性名(ES6)
const key = "email";
const user = {
id: 1,
[key]: "user@example.com"
};
// 添加新属性
person.phone = "13800138000";
// 删除属性
delete person.isStudent;
二、对象方法
1. 对象的内置方法
JavaScript 提供了许多用于操作对象的内置方法:
javascript
// Object.assign() - 合并对象
const target = { a: 1, b: 2 };
const source = { b: 3, c: 4 };
const merged = Object.assign(target, source); // { a: 1, b: 3, c: 4 }
// Object.keys() - 获取对象所有可枚举属性名
const keys = Object.keys(person); // ['name', 'age', 'hobbies', 'address', 'greet', 'phone']
// Object.values() - 获取对象所有可枚举属性值
const values = Object.values(person); // ['张三', 31, [...], {...}, ƒ, '13800138000']
// Object.entries() - 获取对象所有可枚举属性的键值对数组
const entries = Object.entries(person);
// [['name', '张三'], ['age', 31], ...]
// Object.freeze() - 冻结对象(不能添加、删除、修改属性)
const frozen = Object.freeze({ x: 1 });
frozen.x = 2; // 静默失败(严格模式下抛出错误)
// Object.seal() - 密封对象(不能添加、删除属性,但可以修改现有属性)
const sealed = Object.seal({ y: 2 });
sealed.y = 3; // 可以修改
delete sealed.y; // 失败
sealed.z = 4; // 失败
// Object.getPrototypeOf() - 获取对象的原型
const proto = Object.getPrototypeOf(person);
// Object.setPrototypeOf() - 设置对象的原型(性能较差,不推荐频繁使用)
const newProto = { species: "人类" };
Object.setPrototypeOf(person, newProto);
2. 自定义方法
javascript
const calculator = {
value: 0,
add(num) {
this.value += num;
return this; // 支持链式调用
},
subtract(num) {
this.value -= num;
return this;
},
getResult() {
return this.value;
}
};
const result = calculator.add(5).subtract(3).getResult(); // 2
三、对象遍历
1. 遍历对象属性的方式
javascript
// 1. for...in 循环(遍历对象自身和继承的可枚举属性)
for (const key in person) {
if (person.hasOwnProperty(key)) { // 过滤继承的属性
console.log(`${key}: ${person[key]}`);
}
}
// 2. Object.keys() + forEach/map 等数组方法
Object.keys(person).forEach(key => {
console.log(`${key}: ${person[key]}`);
});
// 3. Object.entries() + for...of 循环
for (const [key, value] of Object.entries(person)) {
console.log(`${key}: ${value}`);
}
// 4. Object.getOwnPropertyNames() - 获取所有自有属性(包括不可枚举的)
const allProps = Object.getOwnPropertyNames(person);
四、对象继承与原型链
1. 原型与原型链
javascript
// 每个对象都有一个内部属性 [[Prototype]],指向其原型对象
// 原型链允许对象继承其他对象的属性和方法
// 查看原型
console.log(person.__proto__ === Object.prototype); // true
console.log(Object.getPrototypeOf(person) === Object.prototype); // true
// 创建原型链
const parent = { x: 1 };
const child = Object.create(parent);
child.y = 2;
console.log(child.x); // 1(继承自 parent)
console.log(child.hasOwnProperty('x')); // false
console.log(child.hasOwnProperty('y')); // true
// 原型链的终点是 Object.prototype
console.log(Object.getPrototypeOf(Object.prototype)); // null
2. 构造函数与继承
javascript
function Animal(name) {
this.name = name;
}
// 原型方法
Animal.prototype.speak = function() {
return `${this.name}发出声音`;
};
function Dog(name, breed) {
Animal.call(this, name); // 继承实例属性
this.breed = breed;
}
// 继承原型方法
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
// 重写或添加方法
Dog.prototype.speak = function() {
return `${this.name}汪汪叫`;
};
const myDog = new Dog("小白", "哈士奇");
console.log(myDog.speak()); // 小白汪汪叫
3. ES6 类与继承
javascript
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name}发出声音`;
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 调用父类构造函数
this.breed = breed;
}
speak() {
return `${this.name}汪汪叫`;
}
}
const myDog = new Dog("小白", "哈士奇");
console.log(myDog.speak()); // 小白汪汪叫
五、对象的 this 关键字
javascript
// this 的值取决于函数的调用方式
// 1. 全局作用域
console.log(this === window); // 在浏览器中为 true
// 2. 函数内部(非严格模式)
function showThis() {
console.log(this); // 全局对象(浏览器中为 window)
}
// 3. 方法调用
const obj = {
value: 100,
getValue() {
return this.value;
}
};
console.log(obj.getValue()); // 100
// 4. 构造函数
function MyClass() {
this.value = 200;
}
const instance = new MyClass();
console.log(instance.value); // 200
// 5. 箭头函数(不绑定 this,继承自父级作用域)
const arrowObj = {
value: 300,
getValue: () => {
return this.value; // 全局对象的 value 属性(通常是 undefined)
}
};
console.log(arrowObj.getValue()); // undefined
// 6. 控制 this 的绑定
const anotherObj = { value: 400 };
// call、apply、bind 方法
console.log(obj.getValue.call(anotherObj)); // 400
console.log(obj.getValue.apply(anotherObj)); // 400
const boundFunc = obj.getValue.bind(anotherObj);
console.log(boundFunc()); // 400
六、对象解构赋值
javascript
// ES6 引入的语法,方便提取对象属性
const { name, age } = person;
console.log(name, age); // 张三 31
// 重命名
const { name: personName } = person;
console.log(personName); // 张三
// 默认值
const { email = "未提供邮箱" } = person;
console.log(email); // 未提供邮箱
// 嵌套解构
const { address: { city } } = person;
console.log(city); // 北京
// 剩余参数
const { name, ...rest } = person;
console.log(rest); // 包含除 name 外的所有属性
七、对象的 JSON 处理
javascript
// JSON (JavaScript Object Notation)
// 常用于数据交换
// 对象转 JSON 字符串
const jsonStr = JSON.stringify(person);
console.log(jsonStr);
// 输出: {"name":"张三","age":31,"hobbies":["阅读","游泳","编程"],"address":{"city":"北京","zipCode":"100000"},"phone":"13800138000"}
// 自定义序列化
const jsonStr2 = JSON.stringify(person, ["name", "age"]); // 只包含指定属性
console.log(jsonStr2); // {"name":"张三","age":31}
// 带缩进的 JSON
const jsonStr3 = JSON.stringify(person, null, 2);
console.log(jsonStr3);
// 格式化输出,缩进为 2 个空格
// JSON 字符串转对象
const parsedObj = JSON.parse(jsonStr);
console.log(parsedObj.name); // 张三
八、对象的性能考虑
- 原型继承 vs 类继承:原型继承通常比类继承性能更好
- 对象创建:使用对象字面量比构造函数创建对象更快
- 属性访问:直接属性访问比通过原型链访问更快
- 避免频繁修改原型:
Object.setPrototypeOf()
和__proto__
操作性能较差 - 冻结对象:
Object.freeze()
可以提高对象属性访问速度
九、常见应用场景
- 配置对象:函数接收一个包含多个配置选项的对象
- 数据存储:存储结构化数据
- 命名空间:避免全局变量冲突
- 模块模式:实现私有和公共方法
- 事件处理:事件对象包含事件相关信息
- API 响应处理:处理从服务器返回的 JSON 数据
十、注意事项
- 引用类型:对象是引用类型,赋值和传递时传递的是引用而非副本
- 深拷贝 vs 浅拷贝:
Object.assign()
和扩展运算符(...
)只执行浅拷贝 - 属性枚举顺序:ES2015 规范规定了属性枚举的顺序,但在旧版本浏览器中可能不一致
- 空对象检查:
Object.keys(obj).length === 0
是检查对象是否为空的可靠方法 - 原型链污染:不要修改
Object.prototype
,会影响所有对象
JavaScript 对象是这门语言的核心,掌握对象的各种特性和用法对于编写高质量的 JavaScript 代码至关重要。理解原型链和继承机制,熟练使用对象方法和属性操作,能够让你更加高效地开发 JavaScript 应用。