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

Tho*_*mas 9 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
}
Run Code Online (Sandbox Code Playgroud)

谢谢!

Frx*_*rem 7

创建课程时

class Foo extends Bar {
  constructor(a, b) {
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以稍后通过分配给其原型为该类添加方法:

// methodA(a, b) in class Foo
Foo.prototype.methodA = function(a, b) {
  // do whatever...
}
Run Code Online (Sandbox Code Playgroud)

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

// static staticMethod(a, b) in class Foo
Foo.staticMethod = function(a, b) {
  // do whatever...
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 这很棒,但对于 Typescript 来说,你不能让 methodA 在主类上受到保护/私有(必须是公共的),并且“this”在你的实现中变成任何,所以你会失去代码提示。对于 ES6 来说没问题,但是对于 TS 用户有什么建议吗? (4认同)

And*_*rew 6

这是我的解决方案。它:

  • 使用常规的现代类和.bind()ing, no prototype。(编辑:实际上,请参阅评论以了解更多信息,这可能并不可取。)
  • 与模块一起使用。(如果您不使用模块,我将展示替代选项。)
  • 支持从现有代码轻松转换。
  • 不关心函数顺序(如果你做得正确的话)。
  • 产生易于阅读的代码。
  • 维护成本低。
  • 不幸的是,它不能很好地与同一类中的静态函数配合使用,您需要将它们分开。

首先,将其放入全局文件中或作为第一个<script>标签等:

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

它循环遍历一个对象,并按名称将该对象中的每个函数分配并绑定到该类。这.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() {
        //...
    }
};
Run Code Online (Sandbox Code Playgroud)

最后,在可能依赖这些分离函数的任何其他代码之前,需要单独的文件并在类的函数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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,代码的其余部分将保持不变,就像这些函数一开始就在类中一样:

let msc = new MySplitClass();
msc.myFunction();
msc.myOtherFunction();
Run Code Online (Sandbox Code Playgroud)

同样,由于在实际调用函数之前什么也不会发生,因此只要BindToClass()先调用函数,就无需担心函数顺序。类文件内部和外部的每个函数仍然可以像往常一样访问类内的任何属性或函数。


小智 5

我选择将所有私有变量/函数放在一个名为 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));
  }
}
Run Code Online (Sandbox Code Playgroud)

文件: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;
}
Run Code Online (Sandbox Code Playgroud)

文件:main.js

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

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

输出:

I'm 17 years old
Run Code Online (Sandbox Code Playgroud)

请注意,为了不在 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));
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)