如何始终使 "this" 关键字引用父 class(将子方法绑定到父 class)?
How to always make "this" keyword to reference the parent class (bind child methods to parent class)?
这是我的问题的最简单形式:
class Service1 {
constructor() { this.name = 'service1' }
getThisName() { console.log('Name: ' + (this && this.name)) }
}
const service1 = new Service1();
service1.getThisName() // 'service1' => :)
function mapper(fn, ...params) {
this.name = 'mapper';
// ...params can be parsed or generated here
fn(...params);
}
mapper(service1.getThisName) // undefined => :'(
我知道我可以在 mapper
函数中 fn.bind(service1)
来解决问题,但是由于 fn
是动态的,我不想那样做。
我尝试搜索如何从子方法中获取父 class 但没有得到任何结果。
我希望 mapper
能够调用 class(或对象)的方法,而不会在 readable 和 直截了当 如果可能的话。 mapper
总是在相同的上下文中调用。
javascript有没有办法解决这个问题?
我试过的
function mapper(fn, serviceClass) {
fn.bind(serviceClass)();
}
mapper(service1.getThisName, service1) // OK but is not readable and seems hacky
function mapper(serviceClass, fnName) {
serviceClass[fnName]();
}
mapper(service1, 'getThisName') // OK but autocompletion in the IDE don't work
function mapper(fn) {
fn();
}
mapper(service1.getThisName.bind(service1)) // the "best practice" but in my case not enougth readable
真实用例上下文
在实际用例场景中,mapper
被称为api2service
。顾名思义,它与 expressJs 一起使用,将 api 路由映射到服务。这是代码的简化版本:
app.get(
'get/all/users', // api endpoint
api2service(
userService.getAll, // getAll take filter as the first param
['req.query'] // req.query is the filter and is mapped AND parsed as the first param of the service function. Eg: {name: 'blah'}
)
)
该代码重复了很多次,并且总是在相同的上下文中调用,这就是为什么我需要一些可读的东西,而不是严格遵守良好做法。
直到bind operator proposal is implemented, there's not much you can do about this. Apart from your attempts, you can automatically bind methods at construction time (see also https://github.com/sindresorhus/auto-bind):
function autoBind(obj) {
let proto = Object.getPrototypeOf(obj);
for (let k of Object.getOwnPropertyNames(proto)) {
if (typeof proto[k] === 'function' && k !== 'constructor')
obj[k] = proto[k].bind(obj)
}
}
class Service1 {
constructor() {
this.name = 'service1'
autoBind(this);
}
getThisName() { console.log('Name: ' + (this && this.name)) }
}
function mapper(fn) {
fn();
}
let srv = new Service1
mapper(srv.getThisName)
或使用绑定代理:
function Bound(obj) {
return new Proxy(obj, {
get(target, prop) {
let el = target[prop];
if(typeof el === 'function')
return el.bind(target)
}
})
}
class Service1 {
constructor() {
this.name = 'service1'
}
getThisName() { console.log('Name: ' + (this && this.name)) }
}
function mapper(fn) {
fn();
}
let srv = new Service1
mapper(Bound(srv).getThisName)
这是我的问题的最简单形式:
class Service1 {
constructor() { this.name = 'service1' }
getThisName() { console.log('Name: ' + (this && this.name)) }
}
const service1 = new Service1();
service1.getThisName() // 'service1' => :)
function mapper(fn, ...params) {
this.name = 'mapper';
// ...params can be parsed or generated here
fn(...params);
}
mapper(service1.getThisName) // undefined => :'(
我知道我可以在 mapper
函数中 fn.bind(service1)
来解决问题,但是由于 fn
是动态的,我不想那样做。
我尝试搜索如何从子方法中获取父 class 但没有得到任何结果。
我希望 mapper
能够调用 class(或对象)的方法,而不会在 readable 和 直截了当 如果可能的话。 mapper
总是在相同的上下文中调用。
javascript有没有办法解决这个问题?
我试过的
function mapper(fn, serviceClass) {
fn.bind(serviceClass)();
}
mapper(service1.getThisName, service1) // OK but is not readable and seems hacky
function mapper(serviceClass, fnName) {
serviceClass[fnName]();
}
mapper(service1, 'getThisName') // OK but autocompletion in the IDE don't work
function mapper(fn) {
fn();
}
mapper(service1.getThisName.bind(service1)) // the "best practice" but in my case not enougth readable
真实用例上下文
在实际用例场景中,mapper
被称为api2service
。顾名思义,它与 expressJs 一起使用,将 api 路由映射到服务。这是代码的简化版本:
app.get(
'get/all/users', // api endpoint
api2service(
userService.getAll, // getAll take filter as the first param
['req.query'] // req.query is the filter and is mapped AND parsed as the first param of the service function. Eg: {name: 'blah'}
)
)
该代码重复了很多次,并且总是在相同的上下文中调用,这就是为什么我需要一些可读的东西,而不是严格遵守良好做法。
直到bind operator proposal is implemented, there's not much you can do about this. Apart from your attempts, you can automatically bind methods at construction time (see also https://github.com/sindresorhus/auto-bind):
function autoBind(obj) {
let proto = Object.getPrototypeOf(obj);
for (let k of Object.getOwnPropertyNames(proto)) {
if (typeof proto[k] === 'function' && k !== 'constructor')
obj[k] = proto[k].bind(obj)
}
}
class Service1 {
constructor() {
this.name = 'service1'
autoBind(this);
}
getThisName() { console.log('Name: ' + (this && this.name)) }
}
function mapper(fn) {
fn();
}
let srv = new Service1
mapper(srv.getThisName)
或使用绑定代理:
function Bound(obj) {
return new Proxy(obj, {
get(target, prop) {
let el = target[prop];
if(typeof el === 'function')
return el.bind(target)
}
})
}
class Service1 {
constructor() {
this.name = 'service1'
}
getThisName() { console.log('Name: ' + (this && this.name)) }
}
function mapper(fn) {
fn();
}
let srv = new Service1
mapper(Bound(srv).getThisName)