您现在的位置是:网站首页 > 对象基础文章详情

对象基础

JavaScript中的对象是一种复合数据类型,用于存储键值对的集合。对象可以包含属性和方法,属性是对象的特征,方法是对象的行为。理解对象的基础概念对于编写高效、可维护的代码至关重要。

对象的创建与基本结构

对象可以通过字面量方式直接创建,也可以使用构造函数或Object.create()方法生成。字面量是最常见的方式:

const person = {
  name: '张三',
  age: 30,
  greet: function() {
    console.log(`你好,我是${this.name}`);
  }
};

对象由属性和方法组成,属性是键值对,键是字符串(或Symbol),值可以是任意数据类型。方法本质上是函数类型的属性。

属性的访问与操作

访问对象属性有两种方式:点表示法和方括号表示法:

console.log(person.name); // "张三"
console.log(person['age']); // 30

方括号表示法在属性名包含特殊字符或需要动态访问时特别有用:

const key = 'age';
console.log(person[key]); // 30

添加和修改属性可以直接赋值:

person.job = '工程师'; // 添加新属性
person.age = 31; // 修改现有属性

删除属性使用delete操作符:

delete person.job;

对象的方法

方法是存储在对象属性中的函数。方法可以通过this关键字访问对象的其他属性和方法:

const calculator = {
  value: 0,
  add: function(num) {
    this.value += num;
  },
  subtract: function(num) {
    this.value -= num;
  },
  getValue: function() {
    return this.value;
  }
};

calculator.add(5);
calculator.subtract(2);
console.log(calculator.getValue()); // 3

构造函数与原型

构造函数用于创建特定类型的对象。通过new关键字调用构造函数会创建一个新对象:

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.greet = function() {
    console.log(`你好,我是${this.name}`);
  };
}

const person1 = new Person('李四', 25);
person1.greet(); // "你好,我是李四"

每个函数都有一个prototype属性,用于实现继承和共享方法:

Person.prototype.sayAge = function() {
  console.log(`我今年${this.age}岁`);
};

person1.sayAge(); // "我今年25岁"

对象枚举与属性描述符

可以使用for...in循环枚举对象的可枚举属性:

for (const key in person1) {
  console.log(`${key}: ${person1[key]}`);
}

属性描述符控制属性的行为,可以通过Object.getOwnPropertyDescriptor()获取:

const descriptor = Object.getOwnPropertyDescriptor(person1, 'name');
console.log(descriptor);
/*
{
  value: "李四",
  writable: true,
  enumerable: true,
  configurable: true
}
*/

可以定义新属性或修改现有属性的特性:

Object.defineProperty(person1, 'id', {
  value: '12345',
  writable: false,
  enumerable: false
});

person1.id = '67890'; // 静默失败,严格模式下会报错
console.log(person1.id); // "12345"

对象解构与展开

ES6引入的对象解构可以方便地从对象中提取属性:

const { name, age } = person1;
console.log(name, age); // "李四" 25

对象展开运算符...可以用于合并对象:

const defaults = { color: 'red', size: 'medium' };
const custom = { size: 'large' };

const combined = { ...defaults, ...custom };
console.log(combined); // { color: "red", size: "large" }

对象比较与引用

对象是通过引用比较的,而不是值比较:

const obj1 = { a: 1 };
const obj2 = { a: 1 };
const obj3 = obj1;

console.log(obj1 === obj2); // false
console.log(obj1 === obj3); // true

要比较对象内容,可以手动比较属性或使用工具函数:

function shallowEqual(obj1, obj2) {
  const keys1 = Object.keys(obj1);
  const keys2 = Object.keys(obj2);
  
  if (keys1.length !== keys2.length) return false;
  
  for (const key of keys1) {
    if (obj1[key] !== obj2[key]) return false;
  }
  
  return true;
}

console.log(shallowEqual(obj1, obj2)); // true

对象与JSON

JSON(JavaScript Object Notation)是一种轻量级数据交换格式,与JavaScript对象字面量类似:

const jsonStr = '{"name":"王五","age":28}';
const obj = JSON.parse(jsonStr);
console.log(obj.name); // "王五"

const newJsonStr = JSON.stringify(obj);
console.log(newJsonStr); // '{"name":"王五","age":28}'

对象的高级特性

ES6引入了计算属性名,允许在对象字面量中使用表达式作为属性名:

const propKey = 'user_' + Math.floor(Math.random() * 1000);
const user = {
  [propKey]: '匿名用户'
};
console.log(user); // { user_123: "匿名用户" }

对象方法的简写形式:

const car = {
  brand: 'Toyota',
  // 传统方法定义
  honk: function() {
    console.log('Beep beep!');
  },
  // ES6方法简写
  drive() {
    console.log('Vroom vroom!');
  }
};

对象的不可变性

有时需要创建不可变对象,可以使用以下方法:

  1. 使用Object.freeze()防止对象被修改:
const frozen = Object.freeze({ a: 1 });
frozen.a = 2; // 静默失败,严格模式下会报错
console.log(frozen.a); // 1
  1. 使用Object.seal()防止添加或删除属性,但允许修改现有属性:
const sealed = Object.seal({ a: 1 });
sealed.a = 2; // 允许
sealed.b = 3; // 静默失败
delete sealed.a; // 静默失败

对象与迭代

ES6使对象可迭代,可以通过Symbol.iterator实现:

const iterableObj = {
  data: [1, 2, 3],
  [Symbol.iterator]() {
    let index = 0;
    return {
      next: () => {
        if (index < this.data.length) {
          return { value: this.data[index++], done: false };
        } else {
          return { done: true };
        }
      }
    };
  }
};

for (const num of iterableObj) {
  console.log(num); // 1, 2, 3
}

对象与类

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 dog = new Dog('Rex');
dog.speak(); // "Rex barks."

对象与this绑定

this的指向在JavaScript中是一个常见问题。箭头函数不绑定自己的this,而是继承外层作用域的this

const counter = {
  count: 0,
  increment: function() {
    setInterval(() => {
      this.count++;
      console.log(this.count);
    }, 1000);
  }
};

counter.increment(); // 1, 2, 3...

对象与代理

ES6的Proxy可以拦截和自定义对象的基本操作:

const target = { message: 'hello' };
const handler = {
  get: function(target, prop) {
    if (prop === 'message') {
      return target[prop].toUpperCase();
    }
    return target[prop];
  }
};

const proxy = new Proxy(target, handler);
console.log(proxy.message); // "HELLO"

对象与反射

Reflect API提供了操作对象的方法,与Proxy handlers的方法一一对应:

const obj = { a: 1 };
Reflect.set(obj, 'b', 2);
console.log(Reflect.get(obj, 'b')); // 2
console.log(Reflect.has(obj, 'a')); // true

上一篇: 作用域与闭包

下一篇: 数组基础

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步