【问题标题】:Proper way to dynamically add functions to ES6 classes将函数动态添加到 ES6 类的正确方法
【发布时间】:2015-12-06 10:36:55
【问题描述】:

我有一个带有单个方法 exec(arg1,..,argn) 的简单类,并且我想要一些别名方法,它们使用预定义的参数值(例如 exec_sync = exec.bind(this, true))调用 exec

以下方法可以解决问题:

class Executor {
  constructor() {
    this.exec_sync = this.exec.bind(this, true);
  }

  exec(sync, cmd, args/* ... */) {
    // impl
  }
}

但是我不知道这是否是个好主意,或者这是否符合 ES6 的习惯。

更新日期:

在一个真实的例子中,我有两个嵌套循环,分别有 3 个和 4 个循环,用于向类动态添加总共 12 个别名方法。当您实际上可以利用 JS 作为基于原型的编程语言时,显式定义别名方法将是一项繁琐的任务。

更新 2 - 示例:

假设我们有一个简单的 HTTP 客户端,其方法为 request(method, body),我们想为 GETPUT 等提供别名方法。它看起来如下所示:

class HTTP {
  constructor() {
    ['GET', 'PUT', 'POST', 'DEL'].forEach((method) => {
      this[method] = this.request.bind(this, method);
    }, this);
  }

  request(method, body) {
    // execute the HTTP request
  }
}

【问题讨论】:

  • 为什么不显式地创建多个函数? exec_sync(...args) { return this.exec(true, ...args); }
  • @zerkms 我认为这会更清楚类的作用。我只是对做类似事情的可能性感兴趣。
  • ES6 类只是语法糖。在运行时向对象添加属性方面没有任何改变。

标签: javascript ecmascript-6 idioms


【解决方案1】:

您的解决方案很好,但最好在 prototype 级别创建一次所有这些方法:

['GET', 'PUT', 'POST', 'DEL'].forEach((method) => {
  Executor.prototype[method] = function (body) {
    return this.request(method, body)
  }
})

prototype 方法稍微快一些,因为这段代码只执行一次,而构造函数代码是每次创建新实例时执行的。

prototype 相对于constructor 的另一个优势是它与类继承兼容。因此,如果您稍后扩展您的类,即使您重新定义这些方法中的任何一个,也不会出现任何问题。

顺便说一句,您可以在此处使用require('http').METHODSmethods package 代替HTTP 动词的硬编码数组。

【讨论】:

【解决方案2】:

我不知道这是惯用的(因为它更多的是关于设计,而不是编程语言本身),但我个人认为创建显式函数会更好:

exec_sync(...args) {
    return this.exec(true, ...args); 
}

【讨论】:

  • 在一个真实的例子中,我有 2 个嵌套循环,它们分别有 3 个和 4 个项目,用于将总共 12 个项目动态添加到类中。手动添加所有内容会有点麻烦。
  • @YanFoto 我会考虑把它移到一个单独的类中。
  • 那些方法实际上和语义上属于类。如果我将它们移到一个单独的类中,我仍然需要明确定义它们。还是我在这里遗漏了什么?
  • @YanFoto 那些只是辅助包装器。但同样,这是设计中的品味或偏好问题。对此没有单一的客观答案。
  • 感谢您的帮助。我举了一个例子,在一定程度上说明了这种情况。我想避免下一个开发人员将我的代码视为 ugly :D
【解决方案3】:

我喜欢@leonid 的回答,但是当您使用动态计算属性名称时,有没有办法允许修改。

['VERYBIGNAME', 'VERYBIGNAME2', 'VERYBIGNAME3'].forEach((method) => {
   Executor.prototype[method] = function (body) {
     return this.request(method, body)
   }
})

在您缩小和损坏的 javascript 中,这些 VERYBIGNAME 字符串将存在。

所以如果我能够获得对这些 VERYBIGNAME 函数的引用,我可以使用类似的东西

const references = { VERYBIGNAME1, VERYBIGNAME2, VERYBIGNAME3 };

Object.assign(Executor.prototype, { ...references });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-01-31
    • 1970-01-01
    • 2013-01-16
    • 1970-01-01
    • 2017-10-27
    • 2019-11-08
    • 2022-12-23
    • 2023-03-05
    相关资源
    最近更新 更多