为什么函数的调用成员不能赋值给一个变量?

4

我是一个项目中的转码器,遇到了一个不寻常的极端情况。

我有下面这个:

function a(func){
    return func.call()
}

由于多种原因,转码器希望将其更改为:
function a(func){
   var tmp = func.call;
   var res = tmp()
   return res;
}

然而,调用tmp()时返回tmp不是函数。如果我在这一行调试并暂停,tmp被定义为一个函数。
这与它的签名为function call(){ [native code]}有关吗?
还有其他会触发类似错误的函数吗?
除了简单地不这样做之外,是否有其他方法可以解决这个问题?
编辑: 我发现另一个情况,看起来可能与对象的上下文有关:
a = { toString: null }.propertyIsEnumerable
a("toString")

抛出相同的错误。

编辑:一些背景信息; 我正在编写转码器,它有一个非常特定的用例,即将代码的每一行分解为其最简单的组件部分。也许我无法进一步分离它。使用上面的示例,func.call()是成员访问操作,后跟调用表达式,我想将成员访问和调用表达式分开成两个单独的表达式。


3
任何依赖于 this 值的方法,包括原生的 Function.prototype.call 方法,都存在这个问题。解决方法是将其绑定到对象上,或者不使用这种糟糕的转码。 - Bergi
为什么转码要求你更改函数? - bren
有没有一种方法可以将表达式拆分为其组成部分,同时仍然执行此操作?例如,tmp(func) 而不是 tmp() - Zack Newsham
1
@SpeedyNinja - 这不是一个要求,我正在编写转码器,它有一个非常特定的用例,其中代码的每一行都被分解成最简单的组成部分。可能我无法将其进一步分离。以上面的示例为例,func.call() 是一个成员访问操作,后面跟着一个调用表达式,我想将成员访问和调用表达式分开成两个独立的表达式。 - Zack Newsham
请查看@ZackNewsham的链接:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/call,并查看bergi的评论。 - Jai
如果您想分离/解析代码,不能使用Tern吗? - bren
1个回答

5
如果您想将一个方法存储在变量中,而不是这样做:
 var f = obj.mymethod;
 f();

你可以这样做。
 var f = obj.mymethod.bind(obj);
 f();

很好 - 这似乎是一个通用的解决方案,适用于所有成员函数,包括 call。不幸的是我无法进一步分离它,但这样做已经足够了。 - Zack Newsham
1
我必须加入其他人的意见,认为最好找出一种不需要这样分离方法的方式。JavaScript 更喜欢生成的代码直接写成 obj.method() 的形式。 - hugomg
这是自动化工具的一部分,在这种情况下它并不重要,但这是最容易解释的方式。本质上,该工具的目的是消除任何隐式控制流,并用显式控制流替换它。它还有其他目的 - 但这是所需的预处理。 - Zack Newsham
使用 bind 而不是任何其他函数,意味着我可以向语法解析规则中添加单个异常,例如提取除 bind 以外的所有函数调用。 - Zack Newsham
不知道你的代码转换器是如何工作的,但值得检查一下是否可能将方法与常规函数区别对待,这样你就可以调用 obj.method() 而无需使用 .bind 或类似的技巧。至少,这对于优化来说是有用的。 - hugomg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接