今天有人告诉我,调用一个没有括号的函数是可能的。我能想到的唯一方法是使用像apply
或call
这样的函数。
f.apply(this);
f.call(this);
但是这些需要在apply
和call
上加上括号,这让我们陷入了困境。我还考虑了将函数传递给某种事件处理程序(如setTimeout
)的想法:
setTimeout(f, 500);
但是问题就变成了“如何在没有括号的情况下调用setTimeout
?”“
那么这个谜语的答案是什么呢?如何在不使用括号的情况下调用JavaScript中的函数?
9条答案
按热度按时间628mspwn1#
在ES6中,你有所谓的标记模板文字。
例如:
ufj5ltwl2#
因为Array.constructor是一个
Function
对象。当函数对象被调用时,它们返回一个函数,它的主体是它得到的参数。szqfcxe23#
这是另一个例子,我把函数1传入then函数,没有parantheses,它被调用了。
m528fe3b4#
可以使用匿名函数。它只能使用ES6之前的语法,但它仍然可以工作。
验证码:
并像这样调用它:
ES6之前:
然后像这样调用它
注:现代浏览器似乎不再具有此功能(它在页面加载时调用自己,但当您正常调用它时,它也会工作,但您必须添加一些计数代码以防止它在页面加载时运行)我在Internet Explorer 11上测试了它,它似乎仍然可以工作,但Chrome,Firefox和Edge不工作,这可能只是IE中的一个错误。
ny6fqffe5#
有几种不同的方法可以调用不带括号的函数。
假设你已经定义了这个函数:
然后这里遵循一些不带括号调用
greet
的方法:1.构造函数
使用
new
可以调用不带括号的函数:MDN on the
new
oprator:语法
2.作为
toString
或valueOf
实现toString
和valueOf
是特殊方法:当需要转换时,它们会被隐式调用:你可以(ab)使用这个模式来调用
greet
,不带括号:valueOf
:valueOf
和toString
实际上是从@@toPrimitive方法(从ES6开始)调用的,所以你也可以实现 that 方法:2.b函数原型中覆盖
valueOf
您可以采用前面的想法来覆盖
Function
prototype上的valueOf
方法:一旦你做到了这一点,你可以写:
尽管在代码的后面有括号,但实际的触发调用没有括号。有关此问题的更多信息,请参阅博客"Calling methods in JavaScript, without really calling them"
3.作为Generator
您可以定义一个generator function(使用
*
),它返回一个迭代器。您可以使用spread syntax或for...of
语法调用它。首先,我们需要一个原始
greet
函数的生成器变体:然后我们通过定义@@iterator方法来调用它,而不使用括号:
通常生成器在某处会有一个
yield
关键字,但调用函数时并不需要它。最后一条语句调用函数,但也可以用destructuring来完成:
或
for ... of
结构,但它有自己的括号:请注意,您也可以 * 使用原始的
greet
函数执行上述操作,但它会在执行 *greet
后 * 触发异常(在FF和Chrome上测试)。您可以使用try...catch
块管理异常。4.作为Getter
@jehna1对此有一个完整的答案,所以给予他信用。下面是一种在全局范围内调用函数 * parentheseses-less * 的方法,避免了deprecated
__defineGetter__
方法。它使用Object.defineProperty
代替。我们需要创建一个原始
greet
函数的变体:然后:
将
window
替换为您的全局对象。你可以调用原始的
greet
函数,而不像下面这样在全局对象上留下痕迹:但有人可能会说我们这里确实有括号(尽管它们没有参与实际的调用)。
5.标签函数
从ES6开始,你可以用下面的语法调用一个传递template literal的函数:
请参见“标记模板文字”。
6.代理处理器
从ES6开始,你可以定义一个proxy:
然后阅读任何属性值将调用
greet
:这有许多变化。再举一个例子:
7.作为示例检查器
instanceof
运算符在第二个操作数上执行@@hasInstance
方法,定义如下:q5iwbnjs6#
最简单的方法是使用
new
操作符:虽然这是非正统和不自然的,它的工作,是完全法律的的。
如果不使用参数,则
new
运算符不需要括号。uqxowvwt7#
你可以使用getter和setter。
运行此脚本,只需:
编辑:
我们甚至可以争论!
编辑二:
你也可以定义不带括号的全局函数:
和参数:
免责声明:
正如@MonkeyZeus所说:永远不要在生产环境中使用这段代码,不管你的意图有多好。
1tuwyuhd8#
下面是针对特定情况的example:
虽然该语句实际上不是调用,但会导致未来的调用。
但是,我认为灰色区域可能适合这样的谜语:)
0lvr5msh9#
如果我们接受横向思维的方法,在浏览器中有几个API我们可以滥用来执行任意的JavaScript,包括调用一个函数,而没有任何实际的括号字符。
1.
location
和javascript:
协议:一种这样的技术是在
location
分配上滥用javascript:
协议。示例:
虽然 * 技术上 *
\x28
和\x29
在代码执行后仍然是括号,但实际的(
和)
字符不会出现。括号在JavaScript字符串中转义,该字符串在赋值时进行计算。2.
onerror
和eval
:类似地,根据浏览器的不同,我们可以滥用全局
onerror
,将其设置为eval
,并抛出一些将字符串化为有效JavaScript的东西。这一个是棘手的,因为浏览器在此行为是不一致的,但这里有一个Chrome的例子。Chrome的工作示例(不是Firefox,其他未测试):
这在Chrome中有效,因为
throw'test'
将'Uncaught test'
作为第一个参数传递给onerror
,这几乎是有效的JavaScript。如果我们执行throw';test'
,它将通过'Uncaught ;test'
。现在我们有了有效的JavaScript!只需定义Uncaught
,并将test替换为payload。总结:
这样的代码是真正可怕的,永远不应该被使用,但有时会被用于XSS攻击,所以这个故事的寓意是不要依赖过滤括号来防止XSS。使用CSP来防止此类代码也是一个好主意。