JavaScript中类构造函数与普通函数声明类的差异及继承选型
JavaScript中类的两种创建方式差异与继承适配性
嘿,这个问题问到点子上了!咱们先把两种类创建方式的差异捋明白,再聊聊哪种更适合实现基于类的继承~
一、两种方式的核心差异
虽然你看到它们的Friend.prototype初始都是{constructor: ƒ},但本质上还是有不少区别:
1. 语法层面:语法糖 vs 原生构造逻辑
class是ES6引入的语法糖,写法更贴近传统面向对象语言(比如Java、Python),结构清晰,一眼就能看出类的构造器和方法。- 函数构造函数是ES5及之前的原生写法,把普通函数当作构造器来用,逻辑全靠手动实现,对新手来说门槛更高。
2. 运行特性差异
- 调用限制:
class必须用new关键字调用,直接调用会抛出错误;而函数构造函数如果忘了加new,非严格模式下会把this绑定到全局对象(比如浏览器的window),很容易踩坑。 - 严格模式默认开启:
class内部自动启用严格模式,不用手动加'use strict';函数构造函数需要显式声明才会进入严格模式。 - 方法可枚举性:
class里定义的原型方法默认是不可枚举的(用Object.keys()拿不到);而函数构造函数添加到prototype上的方法是可枚举的。比如:// class写法 class Friend { constructor(name) { this.name = name; } sayHi() { console.log('Hi!'); } } console.log(Object.keys(Friend.prototype)); // 输出: [] // 函数构造函数写法 function Friend(name) { this.name = name; } Friend.prototype.sayHi = function() { console.log('Hi!'); }; console.log(Object.keys(Friend.prototype)); // 输出: ["sayHi"]
二、哪种更适合实现基于类的继承?
答案很明确:如果你的项目环境支持ES6+,优先用class+extends的组合,原因如下:
1. 继承写法更简洁直观
用class实现继承只需要extends关键字,再用super调用父类构造器,逻辑一目了然:
// 父类 class Person { constructor(name) { this.name = name; } greet() { console.log(`Hi, I'm ${this.name}`); } } // 子类继承 class Friend extends Person { constructor(name, hobby) { super(name); // 必须先调用super初始化父类属性 this.hobby = hobby; } showHobby() { console.log(`${this.name} loves ${this.hobby}`); } }
2. 避免手动操作原型链的坑
用函数构造函数实现继承,需要手动做三件事:调用父类构造、设置原型链、修正constructor指向,稍有疏忽就会出错:
// 父类 function Person(name) { this.name = name; } Person.prototype.greet = function() { console.log(`Hi, I'm ${this.name}`); }; // 子类继承 function Friend(name, hobby) { Person.call(this, name); // 手动绑定父类的this this.hobby = hobby; } Friend.prototype = Object.create(Person.prototype); // 手动设置原型链 Friend.prototype.constructor = Friend; // 手动修正constructor指向 Friend.prototype.showHobby = function() { console.log(`${this.name} loves ${this.hobby}`); };
这里如果忘了修正constructor,Friend.prototype.constructor会指向Person;如果用Friend.prototype = Person.prototype直接赋值,还会导致子类修改原型时影响父类,这些坑在class写法里都被JS引擎自动处理了。
3. 支持更多面向对象特性
class还支持静态方法(static关键字)、私有字段(#开头)等特性,这些用函数构造函数实现起来会非常繁琐。
当然,如果需要兼容IE11这类不支持ES6的老环境,那只能用函数构造函数的方式实现继承,但现在大部分项目都已经放弃兼容这类老环境了。
内容的提问来源于stack exchange,提问作者jremi
相关产品推荐
相关产品推荐

