调用没有括号的函数

我今天被告知可以调用没有括号的函数。 我能想到的唯一方法就是使用applycall等函数。

 f.apply(this); f.call(this); 

但是,这些要求括号,并call离开我们在广场。 我也考虑过将函数传递给setTimeout等事件处理程序的想法:

 setTimeout(f, 500); 

但是这个问题变成了“你怎样在没有括号的情况下调用setTimeout ?”

那么这个谜题的解决scheme是什么? 你怎么能在Javascript中调用一个函数而不使用括号?

最简单的方法是使用new操作符:

 function f() { alert('hello'); } new f; 

调用没有括号的函数有几种不同的方法。

假设你定义了这个函数:

 function greet() { console.log('hello'); } 

然后在这里按照一些方式来打电话greet没有括号:

1.作为构造函数

new你可以调用一个没有括号的函数:

 new greet; // parentheses are optional in this construct. 

来自MDN的new作者 :

句法

 new constructor[([arguments])] 

2.对于toStringvalueOf实现

toStringvalueOf是特殊的方法:在需要转换时隐式调用它们:

 var obj = { toString: function() { return 'hello'; } } '' + obj; // concatenation forces cast to string and call to toString. 

你可以(ab)使用这种模式打电话greet没有括号:

 '' + { toString: greet }; 

或者用valueOf

 +{ valueOf: greet }; 

2.b覆盖函数原型中的值

您可以采取以前的想法覆盖Function原型上的valueOf方法:

 Function.prototype.valueOf = function() { this.call(this); // Optional improvement: avoid `NaN` issues when used in expressions. return 0; }; 

一旦你完成了,你可以写:

 +greet; 

虽然在该行中包含括号,但实际的触发调用没有括号。 在博客“在JavaScript中调用方法,而不真正调用它们”

3.作为发电机

你可以定义一个生成器函数 (带* ),它返回一个迭代器 。 您可以使用扩展语法或for...of语法来调用它。

首先,我们需要一个原始greet函数的生成器变体:

 function* greet_gen() { console.log('hello'); } 

然后我们把它叫做括号:

 [...{ [Symbol.iterator]: greet_gen }]; 

通常情况下,发生器会在某个地方有一个yield关键字,但是函数不需要被调用。

最后一个语句调用函数,但是也可以通过解构来完成:

 [,] = { [Symbol.iterator]: greet_gen }; 

或一个for ... of构造:

 for ({} of { [Symbol.iterator]: greet_gen }); 

请注意,您也可以使用原始的greet函数执行上述操作,但在执行greet (在FF和Chrome上进行testing) 之后 ,它将在此过程中触发exception。 你可以用try...catch块pipe理exception。

像Getter一样

@ jehna1对此有一个完整的答案,所以给他信用。 这是一种在全局范围调用无括号的函数的方法,避免了不推荐使用的__defineGetter__方法。 它使用Object.defineProperty来代替。

我们需要为此创build一个原始的greet函数的变体:

 Object.defineProperty(window, 'greet_get', { get: greet }); 

接着:

 greet_get; 

用你的全局对象replacewindow

你可以调用原始的greet函数,而不用在这个全局对象上留下痕迹:

 Object.defineProperty({}, 'greet', { get: greet }).greet; 

但是有人可能会说我们在这里有括号(虽然他们没有参与实际的调用)。

5.作为标签function

有了ES6,你可以调用一个函数来传递一个模板文本 ,语法如下:

 greet``; 

请参阅“标记模板文字” 。 通常情况下,你不会像这里那样传递一个空的字面值,但是作为一个没有括号的调用的例子,它会这样做。

6.作为代理处理程序

在ES6中,您可以定义一个代理 :

 var proxy = new Proxy({}, { get: greet } ); 

然后阅读任何属性值将调用greet

 proxy._; // even if property not defined, it still triggers greet 

这有很多变化。 再举一个例子:

 var proxy = new Proxy({}, { has: greet } ); 1 in proxy; // triggers greet 

你可以使用getters和setter。

 var h = { get ello () { alert("World"); } } 

运行以下脚本:

 h.ello // Fires up alert "world" 

编辑:

我们甚至可以争辩!

 var h = { set ello (what) { alert("Hello " + what); } } h.ello = "world" // Fires up alert "Hello world" 

编辑2:

您也可以定义可以在没有括号的情况下运行的全局函数:

 window.__defineGetter__("hello", function() { alert("world"); }); hello; // Fires up alert "world" 

并与论点:

 window.__defineSetter__("hello", function(what) { alert("Hello " + what); }); hello = "world"; // Fires up alert "Hello world" 

免责声明:

正如@MonkeyZeus所说:不pipe你的意图多好,你永远不要在生产中使用这段代码。

以下是特定情况的示例 :

 window.onload = funcRef; 

虽然这个声明实际上并没有调用,但会导致未来的调用

但是,我想灰色的地方可能是这样的谜语:)

如果我们接受一个横向思维的方法,在浏览器中有几个API可以滥用来执行任意的JavaScript,包括调用一个函数,没有任何实际的括号字符。

1. locationjavascript:协议:

一种这样的技术是在location分配上滥用javascript:协议。

工作示例:

 location='javascript:alert\x281\x29' 

在ES6中,你有所谓的标签模板字面值

例如:

 function foo(val) { console.log(val); } foo`Tagged Template Literals`;