我想调用一个带有自定义 thisArg
的函数。
这看起来很简单,我只需要调用call
:
func.call(thisArg, arg1, arg2, arg3);
但是等等! func.call
可能不是 Function.prototype.call
。
所以我想到了用
Function.prototype.call.call(func, thisArg, arg1, arg2, arg3);
但是等等! Function.prototype.call.call
可能不是 Function.prototype.call
。
因此,假设 Function.prototype.call
是原生的,但考虑到可能已将任意非内部属性添加到其中,ECMAScript 是否提供了一种安全的方法来执行以下操作?
func.[[Call]](thisArg, argumentsList)
最佳答案
这就是鸭子类型的力量(和风险):if typeof func.call === 'function'
,那么您应该将其视为一个普通的可调用函数。 func
的提供者需要确保他们的 call
属性与公共(public)签名相匹配。我实际上在几个地方使用了它,因为 JS 没有提供重载 ()
运算符和提供经典仿函数的方法。
如果你真的需要避免使用 func.call
,我会使用 func()
并要求 func
接受 thisArg
作为第一个参数。由于 func()
没有委托(delegate)给 call
(即,f(g, h)
没有 desugar 给 f。 call(t, g, h)
) 并且您可以在括号的左侧使用变量,它将为您提供可预测的结果。
您还可以在加载库时缓存对 Function.prototype.call
的引用,以防它稍后被替换,并在以后使用它来调用函数。这是 lodash/underscore 用来获取 native 数组方法的模式,但不提供任何实际保证您将获得原始 native 调用方法。它可以变得非常接近并且不是非常丑陋:
const call = Function.prototype.call;
export default function invokeFunctor(fn, thisArg, ...args) {
return call.call(fn, thisArg, ...args);
}
// Later...
function func(a, b) {
console.log(this, a, b);
}
invokeFunctor(func, {}, 1, 2);
这是任何具有多态性的语言中的一个基本问题。在某些时候,您必须相信对象或库会按照其约定行事。与任何其他情况一样,信任但验证:
if (typeof duck.call === 'function') {
func.call(thisArg, ...args);
}
通过类型检查,您还可以进行一些错误处理:
try {
func.call(thisArg, ...args);
} catch (e) {
if (e instanceof TypeError) {
// probably not actually a function
} else {
throw e;
}
}
如果您可以牺牲 thisArg
(或强制它成为一个实参),那么您可以进行类型检查并使用括号调用:
if (func instanceof Function) {
func(...args);
}
关于javascript - 有没有安全的方法调用 `call` 来调用 JavaScript 中的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31076798/