创建类时class语法与函数表示法的差异、行为区别及适用场景
JavaScript 两种类写法的差异、行为对比与选择建议
你给出的两种写法,本质是ES5构造函数+原型模式,和ES6 class语法糖的区别。下面具体拆解它们的行为差异,以及各自的适用场景:
一、核心行为差异
1. 变量提升规则不同
- 第一种写法(函数表达式+原型):变量
Greeter会被提升,但初始值为undefined,如果在声明前调用new Greeter()会直接报错;要是换成function Greeter(...)这种函数声明形式,才会被完整提升,可在声明前实例化。 - 第二种写法(class):class声明不存在变量提升,提前调用
new Greeter()会抛出「无法在初始化前访问Greeter」的错误,必须在声明后才能实例化。
2. 严格模式默认开启
- 第一种写法:除非手动在代码顶部加
'use strict',否则内部运行在非严格模式下,比如给未声明的变量赋值时,会自动挂载到全局对象,不会报错。 - 第二种写法:class内部代码默认开启严格模式,上述操作会直接抛出
ReferenceError,避免非严格模式下的意外行为。
3. 方法可枚举性(针对class内部定义的方法)
如果把greet方法直接写在class内部(比如修改第二种写法为:
class Greeter { greeting; constructor(greeting) { this.greeting = greeting; } greet() { console.log(this.greeting); } }
),此时Greeter.prototype.greet是不可枚举的,用Object.keys(Greeter.prototype)拿不到这个方法;而第一种写法里直接挂载到原型的方法是可枚举的,能被遍历到。
你给出的第二种写法是在外部修改Greeter.prototype.greet,这种情况下和第一种的可枚举性一致。
4. 调用方式强制限制
- 第一种写法:不用
new直接调用Greeter("hello"),非严格模式下this会绑定到全局对象,严格模式下this是undefined,不会直接抛出错误(除非内部用到this的属性)。 - 第二种写法:必须用
new关键字实例化,直接调用Greeter("hello")会抛出「类构造函数不能不用new调用」的TypeError。
5. 私有特性原生支持
- 第一种写法:无法原生实现私有属性/方法,只能通过闭包等方式模拟,模拟的私有属性仍能被特殊手段访问到。
- 第二种写法:可以用
#定义真正的私有字段(比如#greeting;),这类字段只能在class内部访问,外部无法读取或修改,是语法层面的私有支持。
二、选择哪种写法的原因
选第一种(构造函数+原型)
- 需要兼容不支持ES6的旧环境(比如IE11及更早版本);
- 追求极致灵活性,比如动态修改构造函数逻辑、在原型上做复杂的动态扩展;
- 想深入理解JavaScript原型链的底层实现,避免依赖语法糖。
选第二种(class语法糖)
- 代码结构更清晰、语义化更强,和Java、Python等面向对象语言的类写法更接近,可读性更高;
- 原生开启严格模式,减少非严格模式下的潜在bug;
- 继承实现更简洁(用
extends关键字,比ES5的原型继承代码量少很多); - 支持私有字段、静态方法、静态字段等现代面向对象特性,代码更规范易维护。
你的两种写法示例:
第一种写法(ES5函数表达式+原型)
var Greeter = function(greeting) { this.greeting = greeting; }; Greeter.prototype.greet = function() { console.log(this.greeting); } var hello = new Greeter("hello"); hello.greet();
第二种写法(ES6 class+原型扩展)
class Greeter { greeting; constructor(greeting) { this.greeting = greeting; } }; Greeter.prototype.greet = function() { console.log(this.greeting); } var hello = new Greeter("hello"); hello.greet();
内容的提问来源于stack exchange,提问作者user3006927
相关产品推荐
相关产品推荐

