构造函数与类的区别:创建对象的两种方式技术差异咨询
构造函数 vs ES6类:核心差异解析
嘿,这个问题问得特别到位——很多刚摸透JS原型链的开发者都会纠结构造函数和ES6类的区别,我来给你拆解清楚两者的核心差异,结合你贴的代码例子来说:
1. 语法本质与结构清晰度
ES6的class其实是原型继承的语法糖,它并没有改变JS基于原型的本质,但写法更贴近传统面向对象语言(比如Java、Python),结构更规整:
- 你的类示例里,构造逻辑被单独放在
constructor方法中,而doSomething这类实例方法直接写在类体里,一眼就能区分初始化逻辑和实例行为。 - 而ES5构造函数的写法,所有逻辑(包括方法定义)都挤在同一个函数里,像你写的
doSomething是直接挂载在this上的,每个实例都会生成一个新的函数副本,既占内存又不直观。
2. 方法的挂载位置(内存效率差异)
这是两者最关键的实用差异:
- 构造函数版本:你代码里的
this.doSomething = function (){},意味着每创建一个Thing实例,都会新建一个独立的doSomething函数。如果创建1000个实例,就有1000个一模一样的函数,非常浪费内存。如果想让方法共享,你得手动把方法挂到原型上:function Thing(name) { this.name = name; alert("A new thing was created."); } // 手动挂载到原型,所有实例共享 Thing.prototype.doSomething = function() {}; - 类版本:类体里定义的
doSomething()默认就挂载在Thing.prototype上,所有实例共享同一个函数,内存效率更高,不用手动处理原型。
3. 调用限制与安全性
- 类的
constructor必须用new调用:如果直接写Thing(),JS会直接抛出错误,避免了忘记加new导致的意外问题。 - 构造函数的风险:如果忘了加
new调用Thing(),非严格模式下this会绑定到全局对象(比如浏览器里的window),导致name变成全局变量;严格模式下虽然会报错,但不如类的限制直接。
4. 继承的便捷性
如果后续需要实现继承,两者的写法复杂度天差地别:
- 类继承:用
extends和super就能轻松实现,语法简洁不易出错:class SubThing extends Thing { constructor(name, type) { super(name); // 调用父类构造函数 this.type = type; } } - 构造函数继承:需要手动拼接原型链,还要手动调用父类构造函数,步骤繁琐容易踩坑:
function SubThing(name, type) { Thing.call(this, name); // 调用父类构造函数绑定this this.type = type; } // 继承原型方法 SubThing.prototype = Object.create(Thing.prototype); // 修正constructor指向 SubThing.prototype.constructor = SubThing;
5. 其他细节差异
- 静态方法:类可以用
static关键字直接定义静态方法(比如static createThing() { return new Thing(); }),直接通过Thing.createThing()调用;构造函数的静态方法需要手动挂在构造函数本身上(Thing.createThing = function() {}),效果一致但类的写法更规范。 - Getter/Setter:类支持直接定义
get和set访问器,比如:
构造函数要实现同样的效果,得用class Thing { constructor(name) { this._name = name; } get name() { return this._name; } set name(val) { this._name = val; } }Object.defineProperty,写法繁琐很多。
总结一下:ES6类并没有创造新的JS特性,只是让原型继承的写法更简洁、更符合传统OOP的直觉,同时减少了构造函数写法容易出现的错误。如果你的项目支持ES6+,优先用类会更省心;如果要兼容老环境,就用构造函数+原型的写法。
内容的提问来源于stack exchange,提问作者D. Pardal
相关产品推荐
相关产品推荐

