向 ES6 动态添加函数的正确方法 类
Proper way to dynamically add functions to ES6 classes
我有一个简单的 class 和一个方法 exec(arg1,..,argn)
我想有一些别名方法调用 exec
预定义的参数值(例如 exec_sync = exec.bind(this, true)
).
下面的技巧:
class Executor {
constructor() {
this.exec_sync = this.exec.bind(this, true);
}
exec(sync, cmd, args/* ... */) {
// impl
}
}
但是我不知道这是个好主意还是 ES6 惯用的。
更新:
在一个真实的例子中,我有两个嵌套循环,分别有 3 个和 4 个循环,用于动态添加总共 12 个别名方法到 class。当您实际上可以利用 JS 作为基于原型的编程语言时,显式定义别名方法将是一项繁琐的任务。
更新 2 - 示例:
假设我们有一个带有方法 request(method, body)
的简单 HTTP 客户端,我们想为 GET
、PUT
等提供别名方法。它看起来像下面这样:
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);
}
您的解决方案很好,但最好在 prototype
级别上一次创建所有这些方法:
['GET', 'PUT', 'POST', 'DEL'].forEach((method) => {
Executor.prototype[method] = function (body) {
return this.request(method, body)
}
})
prototype
方法稍微快一些,因为这段代码只执行一次,而每次创建新实例时都会执行构造函数代码。
prototype
优于 constructor
的另一个优点是它与 classes 继承兼容。因此,如果您稍后扩展 class,即使您重新定义这些方法中的任何一个,也不会破坏任何内容。
顺便说一句,您可以在这里使用 require('http').METHODS
或 methods
package 而不是硬编码的 HTTP 动词数组。
我喜欢@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 });
我有一个简单的 class 和一个方法 exec(arg1,..,argn)
我想有一些别名方法调用 exec
预定义的参数值(例如 exec_sync = exec.bind(this, true)
).
下面的技巧:
class Executor {
constructor() {
this.exec_sync = this.exec.bind(this, true);
}
exec(sync, cmd, args/* ... */) {
// impl
}
}
但是我不知道这是个好主意还是 ES6 惯用的。
更新:
在一个真实的例子中,我有两个嵌套循环,分别有 3 个和 4 个循环,用于动态添加总共 12 个别名方法到 class。当您实际上可以利用 JS 作为基于原型的编程语言时,显式定义别名方法将是一项繁琐的任务。
更新 2 - 示例:
假设我们有一个带有方法 request(method, body)
的简单 HTTP 客户端,我们想为 GET
、PUT
等提供别名方法。它看起来像下面这样:
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);
}
您的解决方案很好,但最好在 prototype
级别上一次创建所有这些方法:
['GET', 'PUT', 'POST', 'DEL'].forEach((method) => {
Executor.prototype[method] = function (body) {
return this.request(method, body)
}
})
prototype
方法稍微快一些,因为这段代码只执行一次,而每次创建新实例时都会执行构造函数代码。
prototype
优于 constructor
的另一个优点是它与 classes 继承兼容。因此,如果您稍后扩展 class,即使您重新定义这些方法中的任何一个,也不会破坏任何内容。
顺便说一句,您可以在这里使用 require('http').METHODS
或 methods
package 而不是硬编码的 HTTP 动词数组。
我喜欢@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 });