对象基础

对象创建方式

// 1. 对象字面量(最常用)
const person = {
  name: 'Alice',
  age: 30,
  city: 'New York',
  
  // 方法
  greet() {
    return `Hello, I'm ${this.name}`;
  },
  
  // 使用箭头函数(注意this绑定)
  arrowGreet: () => {
    // 箭头函数中的this不指向对象
    return 'Hello from arrow function';
  }
};

console.log(person.name);        // 'Alice'
console.log(person.greet());     // 'Hello, I'm Alice'
console.log(person.arrowGreet()); // 'Hello from arrow function'

// 2. Object构造函数
const person2 = new Object();
person2.name = 'Bob';
person2.age = 25;
person2.greet = function() {
  return `Hi, I'm ${this.name}`;
};

// 3. Object.create()
const personPrototype = {
  greet() {
    return `Hello, I'm ${this.name}`;
  }
};

const person3 = Object.create(personPrototype);
person3.name = 'Charlie';
person3.age = 35;

console.log(person3.greet()); // 'Hello, I'm Charlie'

// 4. 工厂函数
function createPerson(name, age) {
  return {
    name,
    age,
    greet() {
      return `Hello, I'm ${this.name}`;
    }
  };
}

const person4 = createPerson('David', 28);
console.log(person4.greet()); // 'Hello, I'm David'

// 5. 构造函数
function Person(name, age) {
  this.name = name;
  this.age = age;
  this.greet = function() {
    return `Hello, I'm ${this.name}`;
  };
}

const person5 = new Person('Eve', 32);
console.log(person5.greet()); // 'Hello, I'm Eve'

属性操作

const user = {
  firstName: 'John',
  lastName: 'Doe',
  age: 30
};

// 属性访问
console.log(user.firstName);     // 点号访问
console.log(user['lastName']);   // 方括号访问

// 动态属性访问
const prop = 'age';
console.log(user[prop]);         // 30

// 属性赋值
user.email = 'john@example.com'; // 添加新属性
user.age = 31;                   // 修改现有属性
user['phone'] = '123-456-7890';  // 使用方括号添加

// 计算属性名
const prefix = 'user';
const dynamicObj = {
  [prefix + 'Name']: 'Alice',
  [prefix + 'Age']: 25,
  [`${prefix}Email`]: 'alice@example.com'
};

console.log(dynamicObj); // { userName: 'Alice', userAge: 25, userEmail: 'alice@example.com' }

// 属性删除
delete user.phone;
console.log(user.phone); // undefined

// 属性检查
console.log('firstName' in user);           // true
console.log(user.hasOwnProperty('age'));    // true
console.log(user.propertyIsEnumerable('firstName')); // true

// 属性枚举
for (const key in user) {
  console.log(`${key}: ${user[key]}`);
}

// 获取属性名和值
const keys = Object.keys(user);
const values = Object.values(user);
const entries = Object.entries(user);

console.log('Keys:', keys);
console.log('Values:', values);
console.log('Entries:', entries);

// 属性描述符
Object.defineProperty(user, 'id', {
  value: 12345,
  writable: false,    // 不可写
  enumerable: false,  // 不可枚举
  configurable: false // 不可配置
});

console.log(user.id); // 12345
// user.id = 54321;   // 严格模式下会报错
console.log(Object.keys(user)); // id不会出现在keys中

// 获取属性描述符
const descriptor = Object.getOwnPropertyDescriptor(user, 'firstName');
console.log('firstName descriptor:', descriptor);

// 定义多个属性
Object.defineProperties(user, {
  fullName: {
    get() {
      return `${this.firstName} ${this.lastName}`;
    },
    set(value) {
      [this.firstName, this.lastName] = value.split(' ');
    },
    enumerable: true,
    configurable: true
  },
  
  isAdult: {
    get() {
      return this.age >= 18;
    },
    enumerable: true,
    configurable: true
  }
});

console.log(user.fullName); // 'John Doe'
user.fullName = 'Jane Smith';
console.log(user.firstName); // 'Jane'
console.log(user.lastName);  // 'Smith'
console.log(user.isAdult);   // true

对象方法

// Object.assign() - 对象合并
const target = { a: 1, b: 2 };
const source1 = { b: 3, c: 4 };
const source2 = { c: 5, d: 6 };

const merged = Object.assign(target, source1, source2);
console.log(merged); // { a: 1, b: 3, c: 5, d: 6 }
console.log(target); // target也被修改了

// 使用空对象避免修改target
const merged2 = Object.assign({}, target, source1, source2);

// 展开运算符(推荐)
const merged3 = { ...target, ...source1, ...source2 };

// Object.freeze() - 冻结对象
const frozenObj = Object.freeze({
  name: 'Frozen',
  value: 42
});

// frozenObj.name = 'Modified'; // 严格模式下报错
// frozenObj.newProp = 'new';   // 严格模式下报错
console.log(Object.isFrozen(frozenObj)); // true

// 深度冻结
function deepFreeze(obj) {
  Object.getOwnPropertyNames(obj).forEach(prop => {
    if (obj[prop] !== null && typeof obj[prop] === 'object') {
      deepFreeze(obj[prop]);
    }
  });
  return Object.freeze(obj);
}

const deepFrozenObj = deepFreeze({
  level1: {
    level2: {
      value: 'deep'
    }
  }
});

// Object.seal() - 密封对象
const sealedObj = Object.seal({
  name: 'Sealed',
  value: 42
});

sealedObj.name = 'Modified'; // 可以修改现有属性
// sealedObj.newProp = 'new'; // 不能添加新属性
console.log(Object.isSealed(sealedObj)); // true

// Object.preventExtensions() - 阻止扩展
const nonExtensibleObj = Object.preventExtensions({
  name: 'NonExtensible'
});

nonExtensibleObj.name = 'Modified'; // 可以修改
// nonExtensibleObj.newProp = 'new'; // 不能添加
console.log(Object.isExtensible(nonExtensibleObj)); // false

// Object.getPrototypeOf() 和 Object.setPrototypeOf()
const proto = { type: 'prototype' };
const obj = Object.create(proto);

console.log(Object.getPrototypeOf(obj) === proto); // true

const newProto = { type: 'new prototype' };
Object.setPrototypeOf(obj, newProto);
console.log(Object.getPrototypeOf(obj) === newProto); // true

构造函数和new操作符

构造函数基础

// 构造函数定义
function Person(name, age, city) {
  // 实例属性
  this.name = name;
  this.age = age;
  this.city = city;
  
  // 实例方法(不推荐,每个实例都会创建新的函数)
  this.greet = function() {
    return `Hello, I'm ${this.name}`;
  };
}

// 原型方法(推荐)
Person.prototype.introduce = function() {
  return `Hi, I'm ${this.name}, ${this.age} years old, from ${this.city}`;
};

Person.prototype.celebrateBirthday = function() {
  this.age++;
  return `Happy birthday! Now I'm ${this.age}`;
};

// 静态方法
Person.createAdult = function(name, city) {
  return new Person(name, 18, city);
};

// 使用构造函数
const alice = new Person('Alice', 25, 'New York');
const bob = new Person('Bob', 30, 'London');

console.log(alice.introduce());
console.log(bob.celebrateBirthday());

// 使用静态方法
const charlie = Person.createAdult('Charlie', 'Paris');
console.log(charlie.introduce());

// 检查实例
console.log(alice instanceof Person);        // true
console.log(alice.constructor === Person);    // true

// new操作符的工作原理
function myNew(constructor, ...args) {
  // 1. 创建一个新对象
  const obj = {};
  
  // 2. 设置原型链
  Object.setPrototypeOf(obj, constructor.prototype);
  
  // 3. 执行构造函数
  const result = constructor.apply(obj, args);
  
  // 4. 返回对象
  return result instanceof Object ? result : obj;
}

const david = myNew(Person, 'David', 28, 'Tokyo');
console.log(david.introduce());

// 构造函数的问题和解决方案
function Animal(name) {
  this.name = name;
  
  // 问题:每个实例都创建新的函数
  this.speak = function() {
    return `${this.name} makes a sound`;
  };
}

// 解决方案:使用原型
function BetterAnimal(name) {
  this.name = name;
}

BetterAnimal.prototype.speak = function() {
  return `${this.name} makes a sound`;
};

const cat1 = new Animal('Cat1');
const cat2 = new Animal('Cat2');
console.log(cat1.speak === cat2.speak); // false(不同的函数实例)

const dog1 = new BetterAnimal('Dog1');
const dog2 = new BetterAnimal('Dog2');
console.log(dog1.speak === dog2.speak); // true(共享原型方法)

构造函数的高级用法

// 构造函数中的条件逻辑
function User(name, role) {
  this.name = name;
  this.role = role || 'user';
  
  // 根据角色设置权限
  if (this.role === 'admin') {
    this.permissions = ['read', 'write', 'delete'];
  } else if (this.role === 'moderator') {
    this.permissions = ['read', 'write'];
  } else {
    this.permissions = ['read'];
  }
}

User.prototype.hasPermission = function(permission) {
  return this.permissions.includes(permission);
};

User.prototype.addPermission = function(permission) {
  if (!this.hasPermission(permission)) {
    this.permissions.push(permission);
  }
};

const admin = new User('Admin', 'admin');
const user = new User('RegularUser');

console.log(admin.hasPermission('delete')); // true
console.log(user.hasPermission('delete'));  // false

// 构造函数的防御性编程
function SafeConstructor(value) {
  // 确保使用new调用
  if (!(this instanceof SafeConstructor)) {
    return new SafeConstructor(value);
  }
  
  // 参数验证
  if (typeof value !== 'string') {
    throw new TypeError('Value must be a string');
  }
  
  this.value = value;
}

// 可以不使用new调用
const safe1 = SafeConstructor('test');
const safe2 = new SafeConstructor('test2');

console.log(safe1 instanceof SafeConstructor); // true
console.log(safe2 instanceof SafeConstructor); // true

// 私有属性模拟
function PrivateExample(initialValue) {
  // 私有变量
  let privateValue = initialValue;
  let privateCounter = 0;
  
  // 私有方法
  function privateMethod() {
    privateCounter++;
    return `Private method called ${privateCounter} times`;
  }
  
  // 公共方法
  this.getValue = function() {
    return privateValue;
  };
  
  this.setValue = function(value) {
    if (typeof value === 'string') {
      privateValue = value;
      privateMethod();
    }
  };
  
  this.getCallCount = function() {
    return privateCounter;
  };
}

const privateObj = new PrivateExample('initial');
console.log(privateObj.getValue());     // 'initial'
privateObj.setValue('updated');
console.log(privateObj.getValue());     // 'updated'
console.log(privateObj.getCallCount()); // 1
// console.log(privateObj.privateValue); // undefined

原型和原型链

原型基础

// 每个函数都有prototype属性
function MyFunction() {}
console.log(typeof MyFunction.prototype); // 'object'

// 每个对象都有__proto__属性(或使用Object.getPrototypeOf())
const obj = {};
console.log(obj.__proto__ === Object.prototype); // true
console.log(Object.getPrototypeOf(obj) === Object.prototype); // true

// 构造函数、原型和实例的关系
function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  return `${this.name} makes a sound`;
};

const dog = new Animal('Dog');

// 关系验证
console.log(dog.__proto__ === Animal.prototype);           // true
console.log(Animal.prototype.constructor === Animal);      // true
console.log(dog.constructor === Animal);                   // true
console.log(Object.getPrototypeOf(dog) === Animal.prototype); // true

// 原型链查找
console.log(dog.speak());        // 在Animal.prototype中找到
console.log(dog.toString());     // 在Object.prototype中找到
console.log(dog.hasOwnProperty('name')); // true(自有属性)
console.log(dog.hasOwnProperty('speak')); // false(原型属性)

// 动态添加原型方法
Animal.prototype.sleep = function() {
  return `${this.name} is sleeping`;
};

console.log(dog.sleep()); // 'Dog is sleeping'

// 原型属性的枚举
for (const prop in dog) {
  if (dog.hasOwnProperty(prop)) {
    console.log(`Own property: ${prop}`);
  } else {
    console.log(`Inherited property: ${prop}`);
  }
}

// 获取所有自有属性(包括不可枚举的)
const ownProps = Object.getOwnPropertyNames(dog);
console.log('Own properties:', ownProps);

// 检查属性来源
function hasOwnProperty(obj, prop) {
  return Object.prototype.hasOwnProperty.call(obj, prop);
}

function isInherited(obj, prop) {
  return prop in obj && !hasOwnProperty(obj, prop);
}

console.log(hasOwnProperty(dog, 'name'));  // true
console.log(isInherited(dog, 'speak'));    // true

原型链继承

// 基类
function Animal(name) {
  this.name = name;
  this.energy = 100;
}

Animal.prototype.eat = function() {
  this.energy += 10;
  return `${this.name} is eating. Energy: ${this.energy}`;
};

Animal.prototype.sleep = function() {
  this.energy += 20;
  return `${this.name} is sleeping. Energy: ${this.energy}`;
};

// 派生类
function Dog(name, breed) {
  // 调用父类构造函数
  Animal.call(this, name);
  this.breed = breed;
}

// 设置原型链继承
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

// 添加子类特有方法
Dog.prototype.bark = function() {
  this.energy -= 5;
  return `${this.name} is barking! Woof! Energy: ${this.energy}`;
};

// 重写父类方法
Dog.prototype.eat = function() {
  this.energy += 15; // 狗吃得更多
  return `${this.name} the ${this.breed} is eating dog food. Energy: ${this.energy}`;
};

// 创建实例
const myDog = new Dog('Buddy', 'Golden Retriever');

console.log(myDog.eat());   // 调用重写的方法
console.log(myDog.bark());  // 调用子类方法
console.log(myDog.sleep()); // 调用继承的方法

// 验证继承关系
console.log(myDog instanceof Dog);    // true
console.log(myDog instanceof Animal); // true
console.log(myDog instanceof Object); // true

// 另一个派生类
function Cat(name, color) {
  Animal.call(this, name);
  this.color = color;
}

Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;

Cat.prototype.meow = function() {
  this.energy -= 3;
  return `${this.name} is meowing! Meow! Energy: ${this.energy}`;
};

Cat.prototype.climb = function() {
  this.energy -= 10;
  return `${this.name} is climbing. Energy: ${this.energy}`;
};

const myCat = new Cat('Whiskers', 'orange');
console.log(myCat.eat());
console.log(myCat.meow());
console.log(myCat.climb());

// 多层继承
function Puppy(name, breed, age) {
  Dog.call(this, name, breed);
  this.age = age;
}

Puppy.prototype = Object.create(Dog.prototype);
Puppy.prototype.constructor = Puppy;

Puppy.prototype.play = function() {
  this.energy -= 15;
  return `${this.name} the puppy is playing! Energy: ${this.energy}`;
};

// 重写bark方法
Puppy.prototype.bark = function() {
  this.energy -= 2; // 小狗叫声消耗更少能量
  return `${this.name} the puppy is yapping! Yip yip! Energy: ${this.energy}`;
};

const myPuppy = new Puppy('Max', 'Labrador', 3);
console.log(myPuppy.play());
console.log(myPuppy.bark());
console.log(myPuppy.eat());

// 验证多层继承
console.log(myPuppy instanceof Puppy); // true
console.log(myPuppy instanceof Dog);   // true
console.log(myPuppy instanceof Animal); // true

原型链的高级应用

// 混入(Mixin)模式
const Flyable = {
  fly() {
    return `${this.name} is flying!`;
  },
  
  land() {
    return `${this.name} has landed.`;
  }
};

const Swimmable = {
  swim() {
    return `${this.name} is swimming!`;
  },
  
  dive() {
    return `${this.name} is diving deep!`;
  }
};

// 混入函数
function mixin(target, ...sources) {
  sources.forEach(source => {
    Object.getOwnPropertyNames(source).forEach(name => {
      if (name !== 'constructor') {
        target[name] = source[name];
      }
    });
  });
  return target;
}

// 鸟类
function Bird(name) {
  this.name = name;
}

// 混入飞行能力
mixin(Bird.prototype, Flyable);

const eagle = new Bird('Eagle');
console.log(eagle.fly());
console.log(eagle.land());

// 鸭子(既能飞又能游泳)
function Duck(name) {
  this.name = name;
}

mixin(Duck.prototype, Flyable, Swimmable);

const duck = new Duck('Donald');
console.log(duck.fly());
console.log(duck.swim());
console.log(duck.dive());

// 原型链的动态修改
function Vehicle(type) {
  this.type = type;
}

Vehicle.prototype.start = function() {
  return `${this.type} is starting`;
};

const car = new Vehicle('Car');
console.log(car.start()); // 'Car is starting'

// 动态添加方法到原型
Vehicle.prototype.stop = function() {
  return `${this.type} is stopping`;
};

console.log(car.stop()); // 'Car is stopping'

// 替换整个原型(不推荐)
const oldPrototype = Vehicle.prototype;
Vehicle.prototype = {
  start() {
    return `New ${this.type} is starting`;
  },
  
  accelerate() {
    return `${this.type} is accelerating`;
  }
};

// 已存在的实例仍然使用旧原型
console.log(car.start()); // 'Car is starting'(旧方法)
// console.log(car.accelerate()); // TypeError: car.accelerate is not a function

// 新实例使用新原型
const newCar = new Vehicle('New Car');
console.log(newCar.start());      // 'New New Car is starting'
console.log(newCar.accelerate()); // 'New Car is accelerating'
// console.log(newCar.stop());    // TypeError: newCar.stop is not a function

// 原型污染防护
function createSafeObject(proto) {
  const obj = Object.create(proto);
  
  // 防止原型污染
  Object.defineProperty(obj, '__proto__', {
    value: proto,
    writable: false,
    configurable: false
  });
  
  return obj;
}

// 检查原型链
function getPrototypeChain(obj) {
  const chain = [];
  let current = obj;
  
  while (current) {
    chain.push(current.constructor?.name || 'Unknown');
    current = Object.getPrototypeOf(current);
  }
  
  return chain;
}

console.log('Duck prototype chain:', getPrototypeChain(duck));
console.log('Puppy prototype chain:', getPrototypeChain(myPuppy));

ES6类语法

基本类定义

// ES6类语法
class Person {
  // 构造函数
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  
  // 实例方法
  greet() {
    return `Hello, I'm ${this.name}`;
  }
  
  introduce() {
    return `Hi, I'm ${this.name}, ${this.age} years old`;
  }
  
  // Getter
  get info() {
    return `${this.name} (${this.age})`;
  }
  
  // Setter
  set info(value) {
    const [name, age] = value.split(' ');
    this.name = name;
    this.age = parseInt(age);
  }
  
  // 静态方法
  static createAdult(name) {
    return new Person(name, 18);
  }
  
  static compareAge(person1, person2) {
    return person1.age - person2.age;
  }
}

// 使用类
const alice = new Person('Alice', 25);
const bob = new Person('Bob', 30);

console.log(alice.greet());
console.log(alice.info);        // getter
alice.info = 'Alice 26';        // setter
console.log(alice.introduce());

// 静态方法
const charlie = Person.createAdult('Charlie');
console.log(Person.compareAge(alice, bob)); // -4

// 类表达式
const Animal = class {
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    return `${this.name} makes a sound`;
  }
};

// 具名类表达式
const Cat = class Feline {
  constructor(name) {
    this.name = name;
  }
  
  meow() {
    return `${this.name} says meow`;
  }
};

const cat = new Cat('Whiskers');
console.log(cat.meow());

类继承

// 基类
class Animal {
  constructor(name, species) {
    this.name = name;
    this.species = species;
    this.energy = 100;
  }
  
  eat() {
    this.energy += 10;
    return `${this.name} is eating. Energy: ${this.energy}`;
  }
  
  sleep() {
    this.energy += 20;
    return `${this.name} is sleeping. Energy: ${this.energy}`;
  }
  
  get status() {
    if (this.energy > 80) return 'energetic';
    if (this.energy > 50) return 'normal';
    if (this.energy > 20) return 'tired';
    return 'exhausted';
  }
  
  static getSpeciesInfo(species) {
    const info = {
      'dog': 'Loyal companion',
      'cat': 'Independent hunter',
      'bird': 'Flying creature'
    };
    return info[species] || 'Unknown species';
  }
}

// 派生类
class Dog extends Animal {
  constructor(name, breed) {
    super(name, 'dog'); // 调用父类构造函数
    this.breed = breed;
  }
  
  bark() {
    this.energy -= 5;
    return `${this.name} is barking! Woof! Energy: ${this.energy}`;
  }
  
  // 重写父类方法
  eat() {
    this.energy += 15; // 狗吃得更多
    return `${this.name} the ${this.breed} is eating dog food. Energy: ${this.energy}`;
  }
  
  // 调用父类方法
  rest() {
    const result = super.sleep();
    return `${result} (${this.breed} is dreaming)`;
  }
  
  // 重写getter
  get status() {
    const baseStatus = super.status;
    return `${baseStatus} ${this.breed}`;
  }
}

class Cat extends Animal {
  constructor(name, color) {
    super(name, 'cat');
    this.color = color;
  }
  
  meow() {
    this.energy -= 3;
    return `${this.name} is meowing! Meow! Energy: ${this.energy}`;
  }
  
  climb() {
    this.energy -= 10;
    return `${this.name} is climbing. Energy: ${this.energy}`;
  }
  
  hunt() {
    this.energy -= 20;
    return `${this.name} the ${this.color} cat is hunting. Energy: ${this.energy}`;
  }
}

// 使用继承
const myDog = new Dog('Buddy', 'Golden Retriever');
const myCat = new Cat('Whiskers', 'orange');

console.log(myDog.eat());
console.log(myDog.bark());
console.log(myDog.rest());
console.log('Dog status:', myDog.status);

console.log(myCat.meow());
console.log(myCat.hunt());
console.log(myCat.climb());
console.log('Cat status:', myCat.status);

// 静态方法继承
console.log(Dog.getSpeciesInfo('dog'));
console.log(Cat.getSpeciesInfo('cat'));

// 多层继承
class Puppy extends Dog {
  constructor(name, breed, age) {
    super(name, breed);
    this.age = age;
  }
  
  play() {
    this.energy -= 15;
    return `${this.name} the ${this.age}-month-old puppy is playing! Energy: ${this.energy}`;
  }
  
  // 重写bark方法
  bark() {
    this.energy -= 2; // 小狗叫声消耗更少能量
    return `${this.name} the puppy is yapping! Yip yip! Energy: ${this.energy}`;
  }
  
  // 添加新的getter
  get ageGroup() {
    if (this.age < 6) return 'young puppy';
    if (this.age < 12) return 'older puppy';
    return 'young dog';
  }
}

const myPuppy = new Puppy('Max', 'Labrador', 4);
console.log(myPuppy.play());
console.log(myPuppy.bark());
console.log('Puppy age group:', myPuppy.ageGroup);

// 验证继承关系
console.log(myPuppy instanceof Puppy); // true
console.log(myPuppy instanceof Dog);   // true
console.log(myPuppy instanceof Animal); // true

私有字段和方法(ES2022)

// 私有字段和方法
class BankAccount {
  // 私有字段
  #balance = 0;
  #accountNumber;
  #transactions = [];
  
  constructor(accountNumber, initialBalance = 0) {
    this.#accountNumber = accountNumber;
    this.#balance = initialBalance;
    this.#addTransaction('Initial deposit', initialBalance);
  }
  
  // 私有方法
  #addTransaction(type, amount) {
    this.#transactions.push({
      type,
      amount,
      timestamp: new Date(),
      balance: this.#balance
    });
  }
  
  #validateAmount(amount) {
    if (typeof amount !== 'number' || amount <= 0) {
      throw new Error('Amount must be a positive number');
    }
  }
  
  // 公共方法
  deposit(amount) {
    this.#validateAmount(amount);
    this.#balance += amount;
    this.#addTransaction('Deposit', amount);
    return this.#balance;
  }
  
  withdraw(amount) {
    this.#validateAmount(amount);
    
    if (amount > this.#balance) {
      throw new Error('Insufficient funds');
    }
    
    this.#balance -= amount;
    this.#addTransaction('Withdrawal', -amount);
    return this.#balance;
  }
  
  // Getter for balance
  get balance() {
    return this.#balance;
  }
  
  get accountNumber() {
    // 只显示后4位
    return `****${this.#accountNumber.slice(-4)}`;
  }
  
  getTransactionHistory() {
    // 返回交易历史的副本
    return [...this.#transactions];
  }
  
  // 静态私有字段
  static #bankName = 'MyBank';
  static #nextAccountId = 1000;
  
  // 静态私有方法
  static #generateAccountNumber() {
    return `${this.#bankName}-${++this.#nextAccountId}`;
  }
  
  // 静态公共方法
  static createAccount(initialBalance = 0) {
    const accountNumber = this.#generateAccountNumber();
    return new BankAccount(accountNumber, initialBalance);
  }
}

// 使用私有字段的类
const account = BankAccount.createAccount(1000);
console.log('Initial balance:', account.balance);
console.log('Account number:', account.accountNumber);

account.deposit(500);
console.log('After deposit:', account.balance);

account.withdraw(200);
console.log('After withdrawal:', account.balance);

console.log('Transaction history:', account.getTransactionHistory());

// 私有字段无法从外部访问
// console.log(account.#balance); // SyntaxError
// account.#addTransaction('test', 100); // SyntaxError

// 继承中的私有字段
class SavingsAccount extends BankAccount {
  #interestRate;
  
  constructor(accountNumber, initialBalance, interestRate) {
    super(accountNumber, initialBalance);
    this.#interestRate = interestRate;
  }
  
  calculateInterest() {
    // 无法直接访问父类的私有字段
    // const interest = this.#balance * this.#interestRate; // Error
    
    // 必须通过公共方法访问
    const interest = this.balance * this.#interestRate;
    return interest;
  }
  
  addInterest() {
    const interest = this.calculateInterest();
    this.deposit(interest);
    return interest;
  }
  
  get interestRate() {
    return this.#interestRate;
  }
}

const savingsAccount = new SavingsAccount('SAV-001', 1000, 0.05);
console.log('Interest rate:', savingsAccount.interestRate);
console.log('Calculated interest:', savingsAccount.calculateInterest());
savingsAccount.addInterest();
console.log('Balance after interest:', savingsAccount.balance);

抽象类和接口模拟

// 抽象类模拟
class AbstractShape {
  constructor() {
    if (new.target === AbstractShape) {
      throw new Error('Cannot instantiate abstract class');
    }
  }
  
  // 抽象方法
  getArea() {
    throw new Error('Abstract method must be implemented');
  }
  
  getPerimeter() {
    throw new Error('Abstract method must be implemented');
  }
  
  // 具体方法
  describe() {
    return `This shape has an area of ${this.getArea()} and perimeter of ${this.getPerimeter()}`;
  }
}

// 具体实现
class Rectangle extends AbstractShape {
  constructor(width, height) {
    super();
    this.width = width;
    this.height = height;
  }
  
  getArea() {
    return this.width * this.height;
  }
  
  getPerimeter() {
    return 2 * (this.width + this.height);
  }
}

class Circle extends AbstractShape {
  constructor(radius) {
    super();
    this.radius = radius;
  }
  
  getArea() {
    return Math.PI * this.radius * this.radius;
  }
  
  getPerimeter() {
    return 2 * Math.PI * this.radius;
  }
}

// 使用
const rectangle = new Rectangle(5, 3);
const circle = new Circle(4);

console.log(rectangle.describe());
console.log(circle.describe());

// 尝试实例化抽象类会报错
// const shape = new AbstractShape(); // Error

// 接口模拟
function implementsInterface(obj, interfaceMethods) {
  for (const method of interfaceMethods) {
    if (typeof obj[method] !== 'function') {
      throw new Error(`Object must implement ${method} method`);
    }
  }
  return true;
}

// 定义接口
const Drawable = ['draw', 'erase'];
const Movable = ['move', 'rotate'];

// 实现接口的类
class DrawableShape extends AbstractShape {
  constructor() {
    super();
    // 验证接口实现
    implementsInterface(this, Drawable);
    implementsInterface(this, Movable);
  }
  
  draw() {
    return `Drawing ${this.constructor.name}`;
  }
  
  erase() {
    return `Erasing ${this.constructor.name}`;
  }
  
  move(x, y) {
    return `Moving ${this.constructor.name} to (${x}, ${y})`;
  }
  
  rotate(angle) {
    return `Rotating ${this.constructor.name} by ${angle} degrees`;
  }
}

class DrawableRectangle extends DrawableShape {
  constructor(width, height) {
    super();
    this.width = width;
    this.height = height;
  }
  
  getArea() {
    return this.width * this.height;
  }
  
  getPerimeter() {
    return 2 * (this.width + this.height);
  }
}

const drawableRect = new DrawableRectangle(4, 6);
console.log(drawableRect.draw());
console.log(drawableRect.move(10, 20));
console.log(drawableRect.describe());

对象的高级特性

属性描述符详解

// 数据属性描述符
const obj = {};

Object.defineProperty(obj, 'name', {
  value: 'John',
  writable: true,     // 可写
  enumerable: true,   // 可枚举
  configurable: true  // 可配置
});

// 访问器属性描述符
Object.defineProperty(obj, 'fullName', {
  get() {
    return `${this.firstName} ${this.lastName}`;
  },
  set(value) {
    [this.firstName, this.lastName] = value.split(' ');
  },
  enumerable: true,
  configurable: true
});

obj.firstName = 'John';
obj.lastName = 'Doe';
console.log(obj.fullName); // 'John Doe'
obj.fullName = 'Jane Smith';
console.log(obj.firstName); // 'Jane'

// 批量定义属性
Object.defineProperties(obj, {
  age: {
    value: 30,
    writable: true,
    enumerable: true,
    configurable: true
  },
  
  email: {
    value: 'john@example.com',
    writable: false,    // 只读
    enumerable: true,
    configurable: true
  },
  
  id: {
    value: 12345,
    writable: false,
    enumerable: false,  // 不可枚举
    configurable: false // 不可配置
  }
});

// 测试属性特性
console.log('Keys:', Object.keys(obj)); // id不会出现
obj.age = 31; // 可以修改
// obj.email = 'new@example.com'; // 严格模式下报错

// 获取属性描述符
const nameDescriptor = Object.getOwnPropertyDescriptor(obj, 'name');
console.log('Name descriptor:', nameDescriptor);

const allDescriptors = Object.getOwnPropertyDescriptors(obj);
console.log('All descriptors:', allDescriptors);

// 创建不可变对象
function createImmutableObject(data) {
  const obj = {};
  
  for (const [key, value] of Object.entries(data)) {
    Object.defineProperty(obj, key, {
      value: typeof value === 'object' ? createImmutableObject(value) : value,
      writable: false,
      enumerable: true,
      configurable: false
    });
  }
  
  return Object.freeze(obj);
}

const immutableUser = createImmutableObject({
  name: 'Alice',
  age: 25,
  address: {
    city: 'New York',
    country: 'USA'
  }
});

// immutableUser.name = 'Bob'; // 无法修改
// immutableUser.address.city = 'Boston'; // 无法修改
console.log(immutableUser);

Proxy和Reflect

// 基本Proxy用法
const target = {
  name: 'Alice',
  age: 25
};

const proxy = new Proxy(target, {
  // 拦截属性读取
  get(target, property, receiver) {
    console.log(`Getting ${property}`);
    return Reflect.get(target, property, receiver);
  },
  
  // 拦截属性设置
  set(target, property, value, receiver) {
    console.log(`Setting ${property} to ${value}`);
    
    // 验证
    if (property === 'age' && typeof value !== 'number') {
      throw new TypeError('Age must be a number');
    }
    
    return Reflect.set(target, property, value, receiver);
  },
  
  // 拦截属性检查
  has(target, property) {
    console.log(`Checking if ${property} exists`);
    return Reflect.has(target, property);
  },
  
  // 拦截属性删除
  deleteProperty(target, property) {
    console.log(`Deleting ${property}`);
    return Reflect.deleteProperty(target, property);
  }
});

// 使用代理
console.log(proxy.name);  // 触发get拦截器
proxy.age = 26;           // 触发set拦截器
console.log('age' in proxy); // 触发has拦截器
delete proxy.name;        // 触发deleteProperty拦截器

// 数组代理示例
function createObservableArray(arr) {
  return new Proxy(arr, {
    set(target, property, value, receiver) {
      if (property === 'length' || !isNaN(property)) {
        console.log(`Array modified: ${property} = ${value}`);
      }
      return Reflect.set(target, property, value, receiver);
    }
  });
}

const observableArray = createObservableArray([1, 2, 3]);
observableArray.push(4);    // 触发拦截器
observableArray[0] = 10;    // 触发拦截器

// 函数代理
function createLoggingFunction(fn) {
  return new Proxy(fn, {
    apply(target, thisArg, argumentsList) {
      console.log(`Calling function with args:`, argumentsList);
      const result = Reflect.apply(target, thisArg, argumentsList);
      console.log(`Function returned:`, result);
      return result;
    }
  });
}

const add = (a, b) => a + b;
const loggingAdd = createLoggingFunction(add);
const result = loggingAdd(3, 4); // 记录调用和返回值

// 虚拟属性
function createVirtualProperties(obj, virtualProps) {
  return new Proxy(obj, {
    get(target, property, receiver) {
      if (property in virtualProps) {
        return virtualProps[property].call(receiver);
      }
      return Reflect.get(target, property, receiver);
    },
    
    has(target, property) {
      return property in virtualProps || Reflect.has(target, property);
    },
    
    ownKeys(target) {
      return [...Reflect.ownKeys(target), ...Object.keys(virtualProps)];
    }
  });
}

const person = { firstName: 'John', lastName: 'Doe' };
const personWithVirtual = createVirtualProperties(person, {
  fullName() {
    return `${this.firstName} ${this.lastName}`;
  },
  
  initials() {
    return `${this.firstName[0]}.${this.lastName[0]}.`;
  }
});

console.log(personWithVirtual.fullName); // 'John Doe'
console.log(personWithVirtual.initials); // 'J.D.'
console.log('fullName' in personWithVirtual); // true

// 属性验证代理
function createValidatedObject(schema) {
  return new Proxy({}, {
    set(target, property, value, receiver) {
      const validator = schema[property];
      
      if (validator && !validator(value)) {
        throw new Error(`Invalid value for ${property}: ${value}`);
      }
      
      return Reflect.set(target, property, value, receiver);
    }
  });
}

const userSchema = {
  name: value => typeof value === 'string' && value.length > 0,
  age: value => typeof value === 'number' && value >= 0 && value <= 150,
  email: value => typeof value === 'string' && value.includes('@')
};

const validatedUser = createValidatedObject(userSchema);
validatedUser.name = 'Alice';           // 成功
validatedUser.age = 25;                 // 成功
validatedUser.email = 'alice@example.com'; // 成功

try {
  validatedUser.age = -5;               // 抛出错误
} catch (error) {
  console.log('Validation error:', error.message);
}

WeakMap和WeakSet

// WeakMap用于私有属性
const privateData = new WeakMap();

class User {
  constructor(name, email) {
    // 使用WeakMap存储私有数据
    privateData.set(this, {
      name,
      email,
      id: Math.random().toString(36).substr(2, 9)
    });
  }
  
  getName() {
    return privateData.get(this).name;
  }
  
  getEmail() {
    return privateData.get(this).email;
  }
  
  getId() {
    return privateData.get(this).id;
  }
  
  setName(name) {
    const data = privateData.get(this);
    data.name = name;
  }
}

const user1 = new User('Alice', 'alice@example.com');
const user2 = new User('Bob', 'bob@example.com');

console.log(user1.getName()); // 'Alice'
console.log(user2.getName()); // 'Bob'

// 无法直接访问私有数据
console.log(user1.name);      // undefined
console.log(privateData.get(user1)); // 只有在类内部才能访问

// WeakSet用于标记对象
const processedObjects = new WeakSet();

function processObject(obj) {
  if (processedObjects.has(obj)) {
    console.log('Object already processed');
    return;
  }
  
  // 处理对象
  console.log('Processing object:', obj);
  
  // 标记为已处理
  processedObjects.add(obj);
}

const obj1 = { data: 'test1' };
const obj2 = { data: 'test2' };

processObject(obj1); // 处理
processObject(obj1); // 已处理
processObject(obj2); // 处理

// 对象被垃圾回收时,WeakMap/WeakSet中的引用也会被清除
// 这避免了内存泄漏

本章总结

本章深入探讨了JavaScript的对象和原型系统:

  1. 对象基础:学习了多种对象创建方式、属性操作和对象方法
  2. 构造函数:理解了构造函数的工作原理和new操作符的机制
  3. 原型和原型链:掌握了JavaScript的原型继承机制
  4. ES6类语法:学习了现代JavaScript的类定义和继承语法
  5. 高级特性:了解了属性描述符、Proxy、Reflect等高级特性

对象和原型是JavaScript的核心概念,理解它们对于掌握JavaScript的面向对象编程至关重要。这些知识为后续学习模块化、异步编程等高级主题奠定了基础。

下一章我们将学习JavaScript的数组和字符串处理。