对象基础
对象创建方式
// 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的对象和原型系统:
- 对象基础:学习了多种对象创建方式、属性操作和对象方法
- 构造函数:理解了构造函数的工作原理和new操作符的机制
- 原型和原型链:掌握了JavaScript的原型继承机制
- ES6类语法:学习了现代JavaScript的类定义和继承语法
- 高级特性:了解了属性描述符、Proxy、Reflect等高级特性
对象和原型是JavaScript的核心概念,理解它们对于掌握JavaScript的面向对象编程至关重要。这些知识为后续学习模块化、异步编程等高级主题奠定了基础。
下一章我们将学习JavaScript的数组和字符串处理。