【发布时间】:2017-06-27 02:51:49
【问题描述】:
我试图为扩展Function 的类编写概念证明,以演示可以基于另一个函数初始化的函数构造函数,并以下列方式反映this 和arguments:
class Handle extends Function {
constructor(functor) {
super("functor", "slice", `
"use strict";
return functor
.call(this, ...slice.call(arguments, 2));
`);
return this.bind(this, functor, Array.prototype.slice)
}
}
let handle = new Handle(function test() {
console.log(this instanceof Handle, arguments.length)
})
console.log(handle instanceof Handle, handle.length)
handle(1, 2, 3)
但是,根据我对call 和apply 的理解,我认为这会产生相同的行为:
class Handle extends Function {
constructor(functor) {
super("instance", "call", "slice", `
"use strict";
return call(this, instance, ...slice.call(arguments, 3));
`);
return Function.bind
.call(this, functor, this, Function.call, Array.prototype.slice)
}
}
let handle = new Handle(function test() {
console.log(this instanceof Handle, arguments.length)
})
console.log(handle instanceof Handle, handle.length)
handle(1, 2, 3)
这会抛出
Uncaught TypeError: call is not a function
at Function.eval (eval at Handle (js:4), <anonymous>:5:14)
所以call() 函数有问题。我的理解是,如果call() 不是调用表达式的一部分,它的第一个参数将成为被调用的函数,其余参数将成为函数的上下文和参数,有点像Function.call.call(this, instance, ...slice.call(arguments, 3))会做:
class Handle extends Function {
constructor(functor) {
super("instance", "call", "slice", `
"use strict";
return Function.call.call(this, instance, ...slice.call(arguments, 3));
`);
return Function.bind
.call(this, functor, this, Function.call, Array.prototype.slice)
}
}
let handle = new Handle(function test() {
console.log(this instanceof Handle, arguments.length)
})
console.log(handle instanceof Handle, handle.length)
handle(1, 2, 3)
谁能解释我的误解,或者为什么这似乎不是这种情况?
【问题讨论】:
-
查看here 以更轻松地扩展
Function -
@Bergi 虽然我赞成您的回答,因为它很有趣,但它并没有完全利用继承。除了强制将其用作构造函数之外,您的
ExtensibleFunction基本上丢弃了实例化的this,引用您的话,这似乎是在回避问题,而不是以“令人满意”的方式解决它。 -
不,没有
this被丢弃,因为当我们不调用super时它永远不会被实例化 - 我们不想调用super因为这意味着解析和评估每次创建实例时的函数源字符串。 -
@Bergi 哦,这很有趣...我从来没有意识到
super()导致了实例化,我只是认为 ES6 有一些奇怪的约定,如果扩展类的构造函数必须是第一个是明确的。
标签: javascript function call metaprogramming