将函数动态添加到 ES6 类的正确方法

Posted

技术标签:

【中文标题】将函数动态添加到 ES6 类的正确方法【英文标题】:Proper way to dynamically add functions to ES6 classes 【发布时间】: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 类只是语法糖。在运行时向对象添加属性方面没有任何改变。 【参考方案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 动词的硬编码数组。

【讨论】:

谢谢。 http的东西应该是一个例子,我没有在我的代码中使用它:) 让我们continue this discussion in chat.【参考方案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 );

【讨论】:

以上是关于将函数动态添加到 ES6 类的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

将方法添加到调用“super”的动态创建的类

在动态添加的方法中调用 super 的正确方法是啥?

Python3动态添加属性,删除属性,判断属性函数

使用装饰器动态地将方法添加到类中

MFC SDI中 如何为动态创建的按钮添加消息处理函数

react动态添加样式:style和className