我注意到javascript中有一个奇怪的东西。请考虑以下内容:
var fn = ''.toUpperCase.call
console.log(typeof fn); // "function"
fn(); // Uncaught TypeError: `fn` is not a function
以上内容在我的Chrome开发者控制台上执行。版本为43.0.2357.81 m
。
typeof
运算符清楚地表明fn
是一个函数,但错误表明不是。
我注意到Function.apply
至少显示了一些有意义的错误消息。
那么,什么时候是函数,而不是函数?
答案 0 :(得分:19)
Javascript中的上下文总是通过调用函数的方式来建立。
var fn = ''.toUpperCase.call
这将call
函数的原型实现分配给fn
。如果您现在拨打fn()
,则该呼叫没有上下文。 call
将尝试调用与之关联的函数对象。但是,该上下文是在呼叫时建立的。由于您在通话时没有给它任何上下文,call
的某些内部组件会抛出错误。
你必须这样做:
fn.call(''.toUpperCase)
是的,您call
call
函数,建立一个上下文,即toUpperCase
字符串函数。在这种特定情况下,这将导致toUpperCase
内的另一个错误,因为它未绑定到特定上下文。您还需要明确地建立该上下文:
var fn = ''.toUpperCase.call
fn.call(''.toUpperCase.bind(''))
答案 1 :(得分:2)
deceze's answer是正确的,我只是想从不同的角度来解释它。
您的fn
是对Function.prototype.call
的引用,需要使用函数作为其this
引用进行调用,在这种情况下,call
的上下文为{{ 1}},通过String.prototype.toUpperCase
最重要的是,''.toUpperCase
也必须使用特定的上下文调用,字符串为大写。
以下是编写您想要的内容的另一种方法,可以帮助您了解正在发生的事情。
String.prototype.toUpperCase

在您的示例中, var str = 'aaa';
var upper = ''.toUpperCase;
var fn = upper.call;
// Now we have to specify the context for both upper and fn
console.log( fn.call(function() { return upper.call(str)}) ); // AAA
正在尝试调用fn()
,但它未指定上下文,通常默认为call
对象,但在这种情况下它只是它是window
,它会在Chrome中触发一个奇怪的错误(正如您所发现的那样),但Firefox更清楚这个问题,
TypeError:在不兼容的未定义
上调用Function.prototype.call
答案 2 :(得分:1)
那么,什么时候是函数,而不是函数?
该函数是一个函数,但您没有正确执行它,如注释和@deceze的答案所述
我注意到javascript中有一个奇怪的东西。
您似乎对您在测试环境中获得的消息感到困惑,消息并不严格正确。
未捕获的TypeError:
fn
不是函数
当前稳定版本的chrome(我的linux安装上的40.0.2214.91,chrome无法在我的硬件上运行而不进行设置更改),chrome是您测试的环境,给出了一个看似更正确的错误消息感。
Uncaught TypeError: undefined is not a function
那么,你是在问/想要提出一个严肃的问题,还是只是在一个铬版本的错误中点了一点乐趣?