You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:09:22