【问题标题】:How to always make "this" keyword to reference the parent class (bind child methods to parent class)?如何始终使“this”关键字引用父类(将子方法绑定到父类)?
【发布时间】:2021-06-17 15:14:45
【问题描述】:

这是我的问题的最简单形式:

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 是动态的,我不想这样做。
我曾尝试搜索如何从子方法获取父类,但没有得到任何结果。

如果可能的话,我希望mapper 能够以可读直接 的方式调用类(或对象)的方法而不会丢失 this 引用。 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'}
  )
)

该代码重复了很多次,并且总是在相同的上下文中调用,这就是为什么我需要一些可读的东西,而不是严格遵守良好做法。

【问题讨论】:

  • 您希望thismapper 函数体中表示什么?在严格模式下,它将是未定义的......
  • "我知道我可以在 mapper 函数中 fn.bind(service1) 解决问题" 但是为什么不绑定它交给它@987654336 @?您无法绑定给定的匿名函数,因为您无法跟踪将其与什么相关联。但是如果你事先做了,那么mapper就不需要知道什么了。我个人更喜欢mapper(() => service1.getThisName()),因为绑定使它看起来像一个三明治,但它基本上是一样的——你确保正确的this被维护。
  • @trincot 我希望它引用 service1 类
  • @VLAZ 嗨绑定之前作为参数发送也真的很麻烦可读性。我也喜欢 () => 语法,但是对于我需要动态映射(并最终解析)函数参数的实际用例来说并不方便
  • 您也可以在创建时将您的方法绑定到每个实例。重点是您需要在 在别处提供该功能之前执行此操作。没有试图弄清楚它是从哪里来的。

标签: javascript node.js class scope this


【解决方案1】:

在实现bind operator proposal 之前,您对此无能为力。除了您的尝试之外,您还可以在构建时自动绑定方法(另请参阅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)

【讨论】:

  • 我使用了第一个版本,我非常喜欢它,因为它允许我将我的服务无缝地写入 api 文件中。感谢您提供如此定性的答案:)
  • 你是对的。我以为我做了这样的测试,得到了不同的结果。代码确实很可靠。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多