在 JavaScript 里,ES6 引入的 class
语法为实现面向对象编程提供了更简洁、清晰的方式。下面会详细阐述 class
里 constructor
中定义的方法和属性、外部定义的原型方法以及静态方法的区别。
1. 定义方式
constructor
内定义的方法和属性
在 class
里,constructor
是个特殊方法,当创建类的实例时会自动调用。在 constructor
中定义的方法和属性会直接关联到实例对象上。
class Animal {
constructor(name) {
// 定义实例属性
this.name = name;
// 定义实例方法
this.speak = function() {
console.log(`${this.name} 发出声音`);
};
}
}
const dog = new Animal('旺财');
console.log(dog.name); // 输出: 旺财
dog.speak(); // 输出: 旺财 发出声音
在上述代码中,name
属性和 speak
方法都是在 constructor
里定义的,它们属于 dog
这个实例。
原型方法
原型方法是定义在 class
内部但不在 constructor
中的方法,这些方法会被添加到类的原型对象上,所有实例都会共享这些方法。
class Animal {
constructor(name) {
this.name = name;
}
// 定义原型方法
speak() {
console.log(`${this.name} 发出声音`);
}
}
const cat = new Animal('咪咪');
cat.speak(); // 输出: 咪咪 发出声音
这里的 speak
方法是原型方法,cat
实例可以调用它。
静态方法
静态方法使用 static
关键字定义,它属于类本身,而非类的实例。静态方法通常用于实现与类相关的工具函数或工厂方法。
class Animal {
constructor(name) {
this.name = name;
}
static create(name) {
return new Animal(name);
}
}
const bird = Animal.create('啾啾');
console.log(bird.name); // 输出: 啾啾
在这个例子中,create
是静态方法,通过类名 Animal
调用。
2. 访问方式
constructor
内定义的方法和属性
通过实例对象来访问 constructor
中定义的方法和属性。
class Car {
constructor(model) {
this.model = model;
this.start = function() {
console.log(`${this.model} 启动`);
};
}
}
const myCar = new Car('宝马');
console.log(myCar.model); // 输出: 宝马
myCar.start(); // 输出: 宝马 启动
原型方法
同样通过实例对象访问原型方法,方法里的 this
指向调用该方法的实例。
class Car {
constructor(model) {
this.model = model;
}
start() {
console.log(`${this.model} 启动`);
}
}
const myCar = new Car('奔驰');
myCar.start(); // 输出: 奔驰 启动
静态方法
静态方法通过类名直接访问,不能通过实例访问。
class MathUtils {
static add(a, b) {
return a + b;
}
}
const result = MathUtils.add(2, 3);
console.log(result); // 输出: 5
const utils = new MathUtils();
// utils.add(2, 3); // 这会报错,实例不能调用静态方法
3. 内存占用
constructor
内定义的方法和属性
每个实例都会有自己独立的方法和属性副本,要是创建大量实例,会占用较多内存。
class Fruit {
constructor(name) {
this.name = name;
this.describe = function() {
console.log(`这是一个 ${this.name}`);
};
}
}
const apple = new Fruit('苹果');
const banana = new Fruit('香蕉');
// apple 和 banana 都有自己的 describe 方法副本
原型方法
所有实例共享同一个原型方法,只在内存中存在一份,所以内存占用相对较少。
class Fruit {
constructor(name) {
this.name = name;
}
describe() {
console.log(`这是一个 ${this.name}`);
}
}
const apple = new Fruit('苹果');
const banana = new Fruit('香蕉');
// apple 和 banana 共享同一个 describe 方法
静态方法
静态方法属于类本身,只在内存中存在一份,不随实例的创建而复制,内存占用也较少。
4. 继承特性
constructor
内定义的方法和属性
在子类继承父类时,constructor
中定义的方法和属性不会自动被子类继承,需要在子类的 constructor
里手动调用父类的 constructor
并借助 this
来访问这些方法和属性。
class Parent {
constructor() {
this.instanceMethod = function() {
console.log('父类实例方法');
};
}
}
class Child extends Parent {
constructor() {
super();
}
}
const child = new Child();
child.instanceMethod(); // 输出: 父类实例方法
原型方法
原型方法会被所有子类继承,子类实例能直接调用。
class Parent {
prototypeMethod() {
console.log('父类原型方法');
}
}
class Child extends Parent {}
const child = new Child();
child.prototypeMethod(); // 输出: 父类原型方法
静态方法
静态方法也会被子类继承,可通过子类名调用。
class Parent {
static staticMethod() {
console.log('父类静态方法');
}
}
class Child extends Parent {}
Child.staticMethod(); // 输出: 父类静态方法
总结
constructor
内定义的方法和属性:与实例紧密关联,每个实例有独立副本,通过实例访问,内存占用可能较大,继承时需手动处理。- 原型方法:由所有实例共享,通过实例访问,内存占用少,会自动被子类继承。
- 静态方法:属于类本身,通过类名访问,内存占用少,也会被子类继承。
在实际开发中,可依据具体需求来选择合适的定义方式。若方法和属性与特定实例相关,可在 constructor
中定义;若多个实例需共享方法,可定义为原型方法;若方法是与类相关的工具函数,可定义为静态方法。