阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 构造器模式(Constructor)与传统类的区别

构造器模式(Constructor)与传统类的区别

作者:陈川 阅读数:49887人阅读 分类: JavaScript

构造器模式(Constructor)与传统类在JavaScript中都是创建对象的方式,但它们的实现机制和使用场景存在显著差异。构造器模式依赖于函数和原型链,而传统类基于ES6的class语法糖,虽然最终都通过原型继承实现,但写法、功能扩展和细节处理上有所不同。

构造器模式的核心实现

构造器模式通过普通函数模拟类的行为,函数内部通过this绑定实例属性,方法则挂载到函数的原型对象上。这种模式显式依赖原型链,需要手动处理原型关系:

function Animal(name) {
  this.name = name;
  this.speed = 0;
}

Animal.prototype.run = function(speed) {
  this.speed += speed;
  console.log(`${this.name} runs with speed ${this.speed}`);
};

const rabbit = new Animal('White Rabbit');
rabbit.run(5); // White Rabbit runs with speed 5

关键特征包括:

  1. 构造函数首字母通常大写
  2. 实例属性通过this动态绑定
  3. 方法必须显式定义在prototype
  4. 继承需要通过Parent.call(this)和手动设置子类原型

传统类的语法结构

ES6的class提供了更接近传统面向对象语言的语法,但底层仍是原型继承的语法糖:

class Animal {
  constructor(name) {
    this.name = name;
    this.speed = 0;
  }

  run(speed) {
    this.speed += speed;
    console.log(`${this.name} runs with speed ${this.speed}`);
  }
}

const rabbit = new Animal('Black Rabbit');
rabbit.run(10); // Black Rabbit runs with speed 10

与传统构造器相比:

  1. 方法直接定义在类体内
  2. 构造函数使用固定constructor名称
  3. 支持static静态方法
  4. 属性初始化器提案允许直接在类顶层声明属性

继承实现的差异对比

构造器模式的继承需要手动组合原型链和构造函数调用:

function Rabbit(name, earLength) {
  Animal.call(this, name);
  this.earLength = earLength;
}

Rabbit.prototype = Object.create(Animal.prototype);
Rabbit.prototype.constructor = Rabbit;

Rabbit.prototype.jump = function() {
  console.log(`${this.name} jumps!`);
};

而类继承通过extendssuper简化流程:

class Rabbit extends Animal {
  constructor(name, earLength) {
    super(name);
    this.earLength = earLength;
  }

  jump() {
    console.log(`${this.name} jumps!`);
  }
}

关键区别点:

  • 类继承强制要求super()先于this访问
  • 类方法默认不可枚举
  • 子类__proto__指向父类(实现静态继承)

方法定义的内部差异

构造器模式中,方法添加到原型上是可配置、可枚举的:

Object.getOwnPropertyDescriptor(Animal.prototype, 'run');
// {value: ƒ, writable: true, enumerable: true, configurable: true}

而类方法默认是非枚举的:

class Animal {
  run() {}
}
Object.getOwnPropertyDescriptor(Animal.prototype, 'run');
// {value: ƒ, writable: true, enumerable: false, configurable: true}

静态成员的处理方式

构造器模式的静态成员直接附加到函数对象上:

Animal.compare = function(a, b) {
  return a.speed - b.speed;
};

类语法提供专门的static关键字:

class Animal {
  static compare(a, b) {
    return a.speed - b.speed;
  }
}

私有字段的支持情况

现代JavaScript中,类支持实验性的私有字段:

class Animal {
  #secret = 'hidden';
  getSecret() {
    return this.#secret;
  }
}

而构造器模式需要通过闭包或WeakMap模拟私有性:

const Animal = (function() {
  const secrets = new WeakMap();
  
  function Animal(name) {
    secrets.set(this, { secret: 'hidden' });
    this.name = name;
  }

  Animal.prototype.getSecret = function() {
    return secrets.get(this).secret;
  };

  return Animal;
})();

类型检测的不同表现

构造器模式实例通过instanceof检查原型链:

rabbit instanceof Animal; // true

类实例除了instanceof还暴露内部[[IsClassConstructor]]标记:

class Animal {}
typeof Animal; // "function"
Animal.toString(); // "class Animal {...}"

提升行为的区别

函数声明会提升,构造器模式可用在定义前:

new Animal('Early Bird'); // 正常运行
function Animal() {}

类声明存在暂时性死区:

new Animal('Early Bird'); // ReferenceError
class Animal {}

设计模式中的应用场景

构造器模式更灵活,适合需要动态修改原型的场景:

function DynamicClass() {}
// 运行时动态添加方法
if (condition) {
  DynamicClass.prototype.method = function() {};
}

类更适合结构固定的场景,尤其是需要明确继承关系时:

class Component {
  // 明确的接口定义
}
class Button extends Component {
  // 清晰的继承层次
}

性能与内存考量

现代JavaScript引擎对两种形式优化程度相当。但构造器模式可能:

  1. 原型修改会触发隐藏类变化
  2. 动态添加方法影响内联缓存
  3. 大型项目中更难静态分析

类语法由于结构固定,更容易被引擎优化:

// 引擎可以预先确定类结构
class FixedStructure {
  method1() {}
  method2() {}
}

元编程能力的区别

构造器函数作为普通函数,可以直接用apply/call

function Person(name) {
  this.name = name;
}
const obj = {};
Person.call(obj, 'Alice');

类构造函数调用时检查new.target,直接调用会报错:

class Person {
  constructor(name) {
    if (!new.target) throw new Error();
    this.name = name;
  }
}
Person.call(obj, 'Bob'); // Error

装饰器提案的兼容性

当前装饰器提案仅支持类语法:

@decorator
class Animal {
  @methodDecorator
  run() {}
}

构造器模式需要使用高阶函数模拟装饰:

function decoratedConstructor(ctor) {
  return function(...args) {
    // 装饰逻辑
    return new ctor(...args);
  };
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌