【问题标题】:ES6 modules and inheritanceES6 模块和继承
【发布时间】:2016-06-24 13:14:39
【问题描述】:

我有以下 JavaScript 文件:

src/js/classes/Lexus.js:

import {Car} from 'src/js/classes/Car';

export class Lexus extends Car {
  constructor() {
    super("Lexus");
  }
}

src/js/classes/Mercedes.js:

import {Car} from 'src/js/classes/Car';

export class Mercedes extends Car {
  constructor() {
    super("Mercedes");
  }
}

src/js/classes/Car.js:

import {Lexus} from 'src/js/classes/Lexus'; //either of those imports works, but not both!
import {Mercedes} from 'src/js/classes/Mercedes'; //either of those imports works, but not both!

export class Car {
  constructor(make) {
    this.make = make;
  }

  static factory(msg) {
    switch(msg) {
      case "Lexus":
        return new Lexus();
      case "Mercedes":
        return new Mercedes();
    }
  }
}

和 app.js:

import {Lexus} from 'src/js/classes/Lexus';
import {Mercedes} from 'src/js/classes/Mercedes';
import {Car} from 'src/js/classes/Car';

var car = Car.factory("Lexus");
console.log(car);

有趣的是,如果我将 either LexusMercedes 导入 Car 类并调用 app.js 中的工厂方法 - 一切正常;但是,如果我将 both LexusMercedes 导入 Car 类,则会出现错误:

超级表达式必须为 null 或函数,而不是未定义

我错过了什么?

【问题讨论】:

  • 我不确定是否需要在 app.js 中导入 Lexus 和 Mercedes,因为它们不是在那里构建的。
  • 您确定该错误不是基于 Car 和您的特定 make 类相互依赖循环吗?
  • 如果您在每个新语句之后的 case 中加上一个 break 会发生什么?编辑:nvm 你正在返回,所以开关超出范围 sry
  • Sterling Archer,我确实需要将 Lexus 和/或 Mercedes 导入 app.js,以便从工厂方法实例化。
  • @Binvention,如果基于 Car 的错误并使类相互依赖循环,它如何解释任一导入工作但不能同时工作的事实?

标签: javascript inheritance ecmascript-6


【解决方案1】:

通常,您希望具有像这样的循环依赖。 在最好的时候循环依赖,打破一切,不要编译(或转译)。 在最坏的情况下循环依赖,导致合并和版本控制冲突,导致代码很难辨别,看起来它们工作得很好,直到它们停止,一些可怕的状态假设导致了一些可怕的错误。

您的解决方案(如果您在这种继承形式上死心)是将Car 提取到它自己的文件/类中,可以单独导入,并使工厂与类分开.

这在英语中是完全有道理的。
汽车不制造雷克萨斯(Lexi?)。

此外,如果您确实想要保留它(不是一个好主意),那么您应该有一个注册方法,而不是硬编码的解决方案,您可以通过它注册“Lexus”和函数这造就了一辆新的雷克萨斯。

import Car from "./car";
class Lexus extends Car {
  constructor () {
    super("Lexus");
  }
  // starting to look like a bad idea
  static make () {
    return Car.make("Lexus");
  }
  // starting to look worse
  static register () {
    /* this register method does nothing, so that Lexus can't make other cars... */
  }
}

Car.register("Lexus", () => new Lexus());

export default Lexus;

情况会变得更糟,但这已经很糟糕了。

如果你走另一条路:

// carfactory.js

const carTypes = new Map();
class CarFactory {
  static register (name, implementation) {
    carTypes.set(name, implementation);
    return CarFactory;
  }
  static make (name) {
    const makeCar = carTypes.get(name);
    return makeCar();
  }

  register (name, implementation) {
    CarFactory.register(name, implementation);
    return this;
  }
  make (name) { return CarFactory.make(name); }
}

export default CarFactory;


// index.js
import Car from "./classes/car";
import Lexus from "./classes/lexus";

import CarFactory from "./factories/car";

CarFactory
  .register("Lexus", () => new Lexus())
  .register("Bentley", () => new Bentley());

init( CarFactory );

function init (Car) {
  const lexus = Car.make("Lexus");
}

现在,没有班级需要知道他们不应该知道的事情。

【讨论】:

  • 如果我走“另一条路线”,我的汽车课应该是什么样子?
  • @user3715778 class Car { constructor (make) { this.make = make; } }
  • 以及 Car.make() 方法从何而来?
  • 没有Car.make 仔细看看init的内部,以及调用时传入init的内容。工厂的重点是常规代码不必知道或关心它是 CarFactory 还是 Car。它给了一个东西。它使用这个东西,得到它期望的东西,所以它很高兴。
  • map.set(name, implementation); 在 register 方法中,应该是 carTypes.set(name, implementation); 吗?
猜你喜欢
  • 2017-05-21
  • 2023-03-21
  • 2012-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 2019-01-25
相关资源
最近更新 更多