广告

JavaScript 类如何定义?构造函数与类的区别与联系全面解析(含 ES6 语法)

一、JavaScript 类的基本定义与 ES6 语法

使用 ES6 的 class 语法定义类

ES6 中,类(class)成为定义对象模板的主要方式,语义上更加接近传统面向对象语言。通过 class 关键字,可以清晰地描述一个对象的结构与行为,而不是仅仅使用函数。定义类的核心是将成员函数放置在类体内部,以便通过 实例化 创建对象。

通过 class 声明,编译器内部会将其转化为基于原型的实现,但对开发者来说,语法更简洁、可读性更高。构造函数通常作为类的初始化入口,与实例字段一起共同定义对象的初始状态。

class Person {constructor(name, age) {this.name = name;this.age = age;}greet() {console.log(`Hello, I'm ${this.name}`);}
}

在类中定义构造函数与实例方法

class 的内部,constructor用于初始化新实例的字段,实例方法(如 greet())将被放入到对象的原型上,使所有实例共享方法实现,而不是为每个实例独立创建方法。

需要注意的是,创建实例必须使用 new,否则在严格模式下会抛出错误。通过 this 关键字,该实例可以访问和修改自身的字段与行为。

class Person {constructor(name) {this.name = name;}sayName() {console.log(`Name: ${this.name}`);}get upperName() {return this.name.toUpperCase();}set nickname(nick) {this.name = `${nick}`;}
}

二、构造函数与类的区别与联系:核心要点

构造函数与类的核心差异

一个重要的区别在于 可调用性与语法结构:类声明不可被提升(hoisted),且不能在没有 new 的情况下直接执行,违反规则会抛出错误。相比之下,传统的 构造函数(如 ES5 的函数)可以像普通函数一样被调用,若不使用 new,结果往往是意外的全局对象修改。

另一个差异在于 语法糖ES6 的 class 是对原型链的语法糖,底层仍然使用 原型(prototype) 来实现方法的共享与继承,但书写体验更接近其他面向对象语言。声明式的类语法让代码更易读、维护性更高。

// ES5 构造函数
function Person(name) {this.name = name;
}
Person.prototype.greet = function() {console.log('Hi ' + this.name);
};// ES6 Class
class Person {constructor(name) {this.name = name;}greet() {console.log(`Hi ${this.name}`);}
}

两者的联系:底层原型机制的共性

无论使用 构造函数还是 class,对象的实例最终都依赖于 原型对象来共享方法与行为。这意味着:实例方法其实是在原型对象上定义的,所有实例共用同一份实现,能够降低内存开销并提升性能。

此外,构造函数与类之间的映射关系,在编译阶段通常会将 class 转换为等价的原型链定义,例如将方法放在构造函数的 prototype 上,从而实现运行期的多态与继承。

JavaScript 类如何定义?构造函数与类的区别与联系全面解析(含 ES6 语法)

class User {constructor(id) {this.id = id;}
}
const a = new User(1);
const b = new User(2);
console.log(a.__proto__ === b.__proto__); // true

三、扩展与实践:继承、静态成员、封装等在 ES6 语法中的应用

继承与 extends / super

通过 extends 可以让一个类继承另一个类的行为,子类通过 super() 调用父类的构造函数,并在此基础上扩展自己的字段与方法。该特性使得对象模型更加清晰、层次结构更易维护。

使用继承时,实例方法的实现仍然保留在原型链上,而静态方法则直接挂载在类本身,不参与实例的原型链。

class Animal {constructor(name) {this.name = name;}speak() {console.log(`${this.name} makes a sound`);}
}
class Dog extends Animal {constructor(name, breed) {super(name);this.breed = breed;}speak() {console.log(`${this.name} barks`);}
}

静态方法与属性

通过 static 关键字可以在类本身上定义方法,适合实现工具函数、工厂方法等与具体实例无关的行为。静态成员不属于实例,不会出现在实例的原型链上。静态方法通常用于与类相关的通用功能。

结合实际需求,静态成员可以帮助我们在不创建实例的情况下进行校验、计算或构造新的实例对象。

class MathUtil {static add(a, b) {return a + b;}static isNumber(n) {return typeof n === 'number';}
}

原型与封装:访问器(getter/setter)与私有字段的演进

通过 gettersetter 可以实现对字段的封装访问,控制读取与写入时的行为。最新的 JavaScript 提案为私有字段提供了更强的封装能力,确保内部实现对外部不可直接访问。

结合规范实践,可以在类中使用对外暴露的接口来维护对象状态的一致性,避免直接对内部字段进行任意修改。

class Counter {#value = 0; // 私有字段(需支持的环境/编译目标)get value() {return this.#value;}set value(v) {if (typeof v === 'number' && v >= 0) this.#value = v;}
}

广告