在多个文件上拆分Javascript类(ES6)?

时间:2016-10-18 09:06:45

标签: javascript oop ecmascript-6

我有一个Javascript类(在ES6中)已经很长了。为了更好地组织它,我想将它分成2或3个不同的文件。我怎么能这样做?

目前它在一个文件中看起来像这样:

class foo extends bar {
   constructor(a, b) {} // Put in file 1
   methodA(a, b) {} // Put in file 1
   methodB(a, b) {} // Put in file 2
   methodC(a, b) {} // Put in file 2
}

谢谢!

6 个答案:

答案 0 :(得分:5)

创建课程时

class Foo extends Bar {
  constructor(a, b) {
  }
}

稍后您可以通过分配原型来为此类添加方法:

// methodA(a, b) in class Foo
Foo.prototype.methodA = function(a, b) {
  // do whatever...
}

您也可以通过直接分配给类来添加静态方法:

// static staticMethod(a, b) in class Foo
Foo.staticMethod = function(a, b) {
  // do whatever...
}

您可以将这些函数放在不同的文件中,只要它们在声明了类之后运行

但是,构造函数必须始终成为类声明的一部分(您无法将其移动到另一个文件中)。此外,您需要确保定义类方法的文件在使用之前运行。

答案 1 :(得分:3)

我选择将所有privte变量/函数包含在一个称为private的对象中,并将其作为第一个参数传递给外部函数。

通过这种方式,他们可以访问局部变量/函数。

请注意,他们也隐式访问'this'

文件:person.js

const { PersonGetAge, PersonSetAge } = require('./person_age_functions.js');

exports.Person = function () {
  // use privates to store all private variables and functions
  let privates={ }

  // delegate getAge to PersonGetAge in an external file
  // pass this,privates,args
  this.getAge=function(...args) {
    return PersonGetAge.apply(this,[privates].concat(args));
  }

  // delegate setAge to PersonSetAge in an external file
  // pass this,privates,args
  this.setAge=function(...args) {
    return PersonSetAge.apply(this,[privates].concat(args));
  }
}

文件:person_age_functions.js

exports.PersonGetAge =function(privates)
{
  // note: can use 'this' if requires
  return privates.age;
}


exports.PersonSetAge =function(privates,age)
{
  // note: can use 'this' if requires
  privates.age=age;
}

文件:main.js

const { Person } = require('./person.js');

let me = new Person();
me.setAge(17);
console.log(`I'm ${me.getAge()} years old`);

输出:

I'm 17 years old

请注意,为了不重复person.js上的代码,可以在循环中分配所有功能。

例如

person.js选项2

const { PersonGetAge, PersonSetAge } = require('./person_age_functions.js');

exports.Person = function () {
  // use privates to store all private variables and functions
  let privates={ }

  { 
    // assign all external functions
    let funcMappings={
      getAge:PersonGetAge,
      setAge:PersonSetAge
    };


    for (const local of Object.keys(funcMappings))
    {
      this[local]=function(...args) {
        return funcMappings[local].apply(this,[privates].concat(args));
      }
    }
  }
}

答案 2 :(得分:0)

这是我的解决方案。它:

  • 使用常规的现代课程和.bind()进行,而不使用prototype
  • 使用模块。 (如果您不使用模块,我将显示一个替代选项。)
  • 支持从现有代码轻松转换。
  • 不关心功能顺序(如果操作正确)。
  • 产生易于阅读的代码。
  • 维护成本低。
  • 不幸的是,在同一个类中的静态函数不能很好地发挥作用,您需要将它们分开。

首先,将其放置在globals文件中或作为第一个<script>标签等。

BindToClass(functionsObject, thisClass) {
    for (let [ functionKey, functionValue ] of Object.entries(functionsObject)) {
        thisClass[functionKey] = functionValue.bind(thisClass);
    }
}

这将循环遍历一个对象,并将该对象中的每个函数按其名称分配并绑定到该类。 .bind()this上下文的缩写,因此就像在类中一样。

然后将您的函数从类中提取到一个单独的文件中,例如:

//Use this if you're using NodeJS/Webpack. If you're using regular modules,
//use `export` or `export default` instead of `module.exports`.
//If you're not using modules at all, you'll need to map this to some global
//variable or singleton class/object.
module.exports = {
    myFunction: function() {
        //...
    },

    myOtherFunction: function() {
        //...
    }
};

最后,需要一个单独的文件并在该类的 BindToClass 函数中像这样调用constructor() {},然后再执行可能依赖于这些分离函数的任何其他代码:

//If not using modules, use your global variable or singleton class/object instead.
let splitFunctions = require('./SplitFunctions');

class MySplitClass {
    constructor() {
        BindToClass(splitFunctions, this);
    }
}

然后,其余代码将与那些函数以类开头的情况保持相同:

let msc = new MySplitClass();
msc.myFunction();
msc.myOtherFunction();

同样,由于直到真正调用了函数 之前,什么都没有发生,所以只要首先调用BindToClass(),就不必担心函数的顺序。与往常一样,类文件内外的每个函数仍可以访问该类内的任何属性或函数。

答案 3 :(得分:0)

您可以像这样将mixins添加到YourClass:

class YourClass {

  ownProp = 'prop'

}

class Extension {

  extendedMethod() {
    return `extended ${this.ownProp}`
  }

}

addMixins(YourClass, Extension /*, Extension2, Extension3 */)
console.log('Extended method:', (new YourClass()).extendedMethod())

function addMixins() {
  var cls, mixin, arg
  cls = arguments[0].prototype
  for(arg = 1; arg < arguments.length; ++ arg) {
    mixin = arguments[arg].prototype
    Object.getOwnPropertyNames(mixin).forEach(prop => {
      if (prop == 'constructor') return
      if (Object.getOwnPropertyNames(cls).includes(prop))
        throw(`Class ${cls.constructor.name} already has field ${prop}, can't mixin ${mixin.constructor.name}`)
      cls[prop] = mixin[prop]
    })
  }
}

答案 4 :(得分:0)

我的解决方案类似于by Erez(在文件中声明方法,然后在构造函数中将方法赋值给this),但是

  • 它使用类语法而不是将构造函数声明为函数
  • 没有真正私有字段的选项 - 但这无论如何都不是这个问题的问题
  • 它没有调用 .apply() 的层 - 函数直接插入到实例中
  • 每个文件一种方法:这对我有用,但可以修改解决方案
  • 导致更简洁的类声明

1。在构造函数中赋值方法

C.js

class C {
  constructor() {
    this.x = 1;
    this.addToX = require('./addToX');
    this.incX = require('./incX');
  }
}

addToX.js

function addToX(val) {
  this.x += val;
  return this.x;
}

module.exports = addToX;

incX.js

function incX() {
  return this.addToX(1);
}

module.exports = incX;

2.相同,但带有 instance fields syntax

<块引用>

请注意,此语法目前为 Stage 3 proposal
但它适用于 Node.js 14——我关心的平台。

C.js

class C {
  x = 1;
  addToX = require('./addToX');
  incX = require('./incX');
}

测试

const c = new C();
console.log('c.incX()', c.incX());
console.log('c.incX()', c.incX());

答案 5 :(得分:-2)

  

我有一个Javascript类(在ES6中)已经很长了。为了更好地组织它,我想将它分成2或3个不同的文件。我怎么能这样做?

如果你不想要处理程序,你必须在文件1中声明该类,使其成为全局类(就像我之前评论过的那样......之前),并在其他文件中可以(重新)在这个类的原型对象中指定属性(这是一个函数)。

如果您要退出课程块表达,那就是事实。