JavaScript 对象学习总结

发布于:2025-06-09 ⋅ 阅读:(21) ⋅ 点赞:(0)

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); // 张三

八、对象的性能考虑

  1. 原型继承 vs 类继承:原型继承通常比类继承性能更好
  2. 对象创建:使用对象字面量比构造函数创建对象更快
  3. 属性访问:直接属性访问比通过原型链访问更快
  4. 避免频繁修改原型Object.setPrototypeOf() 和 __proto__ 操作性能较差
  5. 冻结对象Object.freeze() 可以提高对象属性访问速度

九、常见应用场景

  1. 配置对象:函数接收一个包含多个配置选项的对象
  2. 数据存储:存储结构化数据
  3. 命名空间:避免全局变量冲突
  4. 模块模式:实现私有和公共方法
  5. 事件处理:事件对象包含事件相关信息
  6. API 响应处理:处理从服务器返回的 JSON 数据

十、注意事项

  1. 引用类型:对象是引用类型,赋值和传递时传递的是引用而非副本
  2. 深拷贝 vs 浅拷贝Object.assign() 和扩展运算符(...)只执行浅拷贝
  3. 属性枚举顺序:ES2015 规范规定了属性枚举的顺序,但在旧版本浏览器中可能不一致
  4. 空对象检查Object.keys(obj).length === 0 是检查对象是否为空的可靠方法
  5. 原型链污染:不要修改 Object.prototype,会影响所有对象

JavaScript 对象是这门语言的核心,掌握对象的各种特性和用法对于编写高质量的 JavaScript 代码至关重要。理解原型链和继承机制,熟练使用对象方法和属性操作,能够让你更加高效地开发 JavaScript 应用。