这是一种创建可调用对象的方法,这些对象正确引用其对象成员,并保持正确的继承,而不会弄乱原型。
简单地:
class ExFunc extends Function {
constructor() {
super('...args', 'return this.__self__.__call__(...args)')
var self = this.bind(this)
this.__self__ = self
return self
}
// Example `__call__` method.
__call__(a, b, c) {
return [a, b, c];
}
}
扩展这个类并添加一个__call__
方法,更多如下...
代码和注释中的解释:
// This is an approach to creating callable objects
// that correctly reference their own object and object members,
// without messing with prototypes.
// A Class that extends Function so we can create
// objects that also behave like functions, i.e. callable objects.
class ExFunc extends Function {
constructor() {
super('...args', 'return this.__self__.__call__(...args)');
// Here we create a function dynamically using `super`, which calls
// the `Function` constructor which we are inheriting from. Our aim is to create
// a `Function` object that, when called, will pass the call along to an internal
// method `__call__`, to appear as though the object is callable. Our problem is
// that the code inside our function can't find the `__call__` method, because it
// has no reference to itself, the `this` object we just created.
// The `this` reference inside a function is called its context. We need to give
// our new `Function` object a `this` context of itself, so that it can access
// the `__call__` method and any other properties/methods attached to it.
// We can do this with `bind`:
var self = this.bind(this);
// We've wrapped our function object `this` in a bound function object, that
// provides a fixed context to the function, in this case itself.
this.__self__ = self;
// Now we have a new wrinkle, our function has a context of our `this` object but
// we are going to return the bound function from our constructor instead of the
// original `this`, so that it is callable. But the bound function is a wrapper
// around our original `this`, so anything we add to it won't be seen by the
// code running inside our function. An easy fix is to add a reference to the
// new `this` stored in `self` to the old `this` as `__self__`. Now our functions
// context can find the bound version of itself by following `this.__self__`.
self.person = 'Hank'
return self;
}
// An example property to demonstrate member access.
get venture() {
return this.person;
}
// Override this method in subclasses of ExFunc to take whatever arguments
// you want and perform whatever logic you like. It will be called whenever
// you use the obj as a function.
__call__(a, b, c) {
return [this.venture, a, b, c];
}
}
// A subclass of ExFunc with an overridden __call__ method.
class DaFunc extends ExFunc {
constructor() {
super()
this.a = 'a1'
this.b = 'b2'
this.person = 'Dean'
}
ab() {
return this.a + this.b
}
__call__(ans) {
return [this.ab(), this.venture, ans];
}
}
// Create objects from ExFunc and its subclass.
var callable1 = new ExFunc();
var callable2 = new DaFunc();
// Inheritance is correctly maintained.
console.log('\nInheritance maintained:');
console.log(callable2 instanceof Function); // true
console.log(callable2 instanceof ExFunc); // true
console.log(callable2 instanceof DaFunc); // true
// Test ExFunc and its subclass objects by calling them like functions.
console.log('\nCallable objects:');
console.log( callable1(1, 2, 3) ); // [ 'Hank', 1, 2, 3 ]
console.log( callable2(42) ); // [ 'a1b2', Dean', 42 ]
// Test property and method access
console.log(callable2.a, callable2.b, callable2.ab())
在 repl.it 上查看
进一步解释bind
:
function.bind()
工作起来很像function.call()
,它们共享一个类似的方法签名:
fn.call(this, arg1, arg2, arg3, ...);
更多关于mdn
fn.bind(this, arg1, arg2, arg3, ...);
更多关于mdn
在这两个参数中,第一个参数重新定义this
了函数内部的上下文。其他参数也可以绑定到一个值。但是,在call
立即使用绑定值调用函数的地方,bind
返回一个“异国情调”的函数对象,该对象透明地包装了原始函数this
和任何预设的参数。
所以当你定义一个函数时bind
,它的一些参数:
var foo = function(a, b) {
console.log(this);
return a * b;
}
foo = foo.bind(['hello'], 2);
您仅使用其余参数调用绑定函数,其上下文已预设,在本例中为['hello']
。
// We pass in arg `b` only because arg `a` is already set.
foo(2); // returns 4, logs `['hello']`