自动绑定 JS 类方法的好方法是啥?
Posted
技术标签:
【中文标题】自动绑定 JS 类方法的好方法是啥?【英文标题】:What is a good way to automatically bind JS class methods?自动绑定 JS 类方法的好方法是什么? 【发布时间】:2019-10-23 12:06:56 【问题描述】:我厌倦了写这样的代码:
class Something
constructor()
this.method = this.method.bind(this);
this.anotherOne = this.anotherOne.bind(this);
// ...
这很耗时,而且很容易忘记绑定方法。我知道类字段提案,但它仍处于第 3 阶段,似乎与 some issues 一起提供。
我当前的解决方案(基于this answer)如下所示:
class Something
constructor()
// Get all defined class methods
const methods = Object.getOwnPropertyNames(Object.getPrototypeOf(this));
// Bind all methods
methods
.filter(method => (method !== 'constructor'))
.forEach((method) => this[method] = this[method].bind(this); );
这似乎可行,但我想知道是否有更好的方法,或者这种方法是否存在我不知道的问题。
更新:为什么要这样做?
我遇到的问题是,如果我不在构造函数中绑定我的类函数,我必须记住稍后“正确”调用它们。例如:
const classInstance = new Something();
// This fails for a non-obvious reason
someAction()
.then(classInstance.method);
// This works of course but looks like we created a useless function if you don't know better
someAction()
.then(result => classInstance.method(result));
【问题讨论】:
我会将绑定提取到一个单独的函数中,而不是在构造函数中 一个选项,考虑到您只需要绑定在不同上下文(通常是事件处理程序)中调用的方法,是使用箭头函数来调用这些方法而不更改上下文。 你使用 ES5 而不是胖箭头语法有什么原因吗? 你为什么觉得你必须这样做?this.self = this
方法怎么样?这里不讨论了……
【参考方案1】:
在ES6中使用fat arrow函数(一般称为箭头函数)
anotherOne = ()=>
...
像这样调用onClick=this.anotherOne;
无需在构造函数中绑定
来自ECMA spec
任何对参数、super、this 或 new.target 的引用 ArrowFunction 必须解析为词法封闭中的绑定 环境。通常这将是一个函数环境 立即封闭函数。
【讨论】:
我根本看不到如何将对象的方法绑定到它的实例。似乎没有回答所提出的问题。 OP 已经提到了这一点,并表示他不喜欢随之而来的问题。 @jfriend00 ?这是类字段语法,这意味着函数内部的this
将绑定到实例而没有额外的.bind
,对吗?可能不是 OP 想要的,因为他明确提到它是一种被丢弃的可能性,尽管
@CertainPerformance - 好吧,答案没有显示足够的定义上下文来知道他们在做什么。当然对我来说并不明显。
您似乎没有提到这依赖于 public class fields 功能。【参考方案2】:
你也可以像这样使用auto-bind
来自用法示例:
const autoBind = require('auto-bind');
class Unicorn
constructor(name)
this.name = name;
autoBind(this);
message()
return `$this.name is awesome!`;
const unicorn = new Unicorn('Rainbow');
// Grab the method off the class instance
const message = unicorn.message;
// Still bound to the class instance
message();
//=> 'Rainbow is awesome!'
// Without `autoBind(this)`, the above would have resulted in
message();
//=> Error: Cannot read property 'name' of undefined
【讨论】:
感谢分享。如果没有 sindresorhus,JS 会在哪里? ;)【参考方案3】:你可以使用 ES6 箭头函数:
method = () =>
//Do stuff
如docs中所述:
箭头函数表达式是正则函数表达式的语法紧凑替代方案,尽管它自己没有绑定到 this、arguments、super 或 new.target 关键字。
【讨论】:
我根本看不到如何将对象的方法绑定到它的实例。似乎没有回答所提出的问题。 OP 已经提到了这一点,并表示他不喜欢随之而来的问题。【参考方案4】:回答这个问题似乎有点晚了,但没有公认的答案,所以我会尽我最大的努力让人们在我之后来到这里。
要为所有方法自动绑定this
,可以使用“箭头”函数:
class Something
constructor()
// Don't need to bind `this`
doSomething = () =>
console.log(this); // `this` will be pointed to the instance
const s = new Something();
s.doSomething(); // => `this` is pointed to `s`
注意:请确保扩展此类Something
的类不会在其constructor
中使用doSomething
方法(例如:super.doSomething()
),否则会报错。
回答更新后的问题:如果您不使用.call()
或.apply()
手动绑定this
,则this
的值取决于该方法的调用方式
例如:
class Something
constructor()
// didn't bind `this` here
doSomething()
console.log(this);
const s = new Something();
const funcA = s.doSomething;
const object =
funcB: s.doSomething,
;
// these ways of calling `.doSomething()` result in different values of `this`:
funcA(); // => `this` is pointed to the global variable (`window` in browser environment)
window.funcA(); // => same as `funcA()`
s.doSomething(); // => `this` is pointed to `s`
object.funcB(); // =? `this` is pointed to `object`
除此之外,.then()
方法的实现类似于这样:
class Promise
// ...
then(callback)
// code...
callback(); // notice how the `callback` is called - not as a method of an object
// code...
在您的代码示例中,将回调传递给.then()
方法的方式将影响回调中this
的值:
const classInstance = new Something();
// `this` inside `classInstance.method` is pointed to `this` inside the
// `.then` method, not the `classInstance`, as `classInstance.method()`
// will be called as `callback()`
someAction()
.then(classInstance.method);
// `this` inside `classInstance.method` is pointed to `classInstance`,
// as the way the anonymous "arrow" function is called does not affect the way
// `classInstance.method` is called, so `this`'s value is controlled by the way
// you call it inside the callback (anonymous "arrow" function) of `.then()`
// method.
someAction()
.then(result => classInstance.method(result));
【讨论】:
以上是关于自动绑定 JS 类方法的好方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
将 SwiftUI 警报或操作表绑定到值类型模型属性的可选性(当属性为 nil 时显示视图)的好方法是啥?
测试自定义视图的 onMeasure/onLayout/onDraw 方法的好方法是啥?
在 C++ 中声明实例变量而不构造它们的好方法是啥? [关闭]