调用没有括号的函数

时间:2016-03-11 20:44:23

标签: javascript

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

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

但这些要求在applycall上使用括号,将我们留在第一个方位。我还考虑过将函数传递给某种事件处理程序的想法,例如setTimeout

setTimeout(f, 500);

然后问题就变成“你如何在没有括号的情况下调用setTimeout?”

那么这个谜语的解决方案是什么?如何在不使用括号的情况下在Javascript中调用函数?

7 个答案:

答案 0 :(得分:375)

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

我们假设您已定义此功能:

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

然后在这里按照一些方法调用greet而不用括号:

1。作为构造函数

使用new,您可以调用不带括号的函数:

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

来自MDN on the new oprator

  

<强>语法

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覆盖函数原型

中的valueOf

您可以采用上一个想法覆盖Function prototype上的valueOf方法:

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

完成后,您可以写下:

+greet;

虽然在线下有括号,但实际的触发调用没有括号。在博客"Calling methods in JavaScript, without really calling them"

中详细了解相关信息

3。作为生成器

您可以定义generator function*),返回iterator。您可以使用spread syntaxfor...of语法来调用它。

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

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

然后我们称之为没有括号:

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

通常情况下,生成器会在某处使用yield关键字,但函数不需要调用它。

最后一个语句调用该函数,但也可以使用destructuring

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

for ... of构造,但它有自己的括号:

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

请注意,您可以使用原始greet函数执行上述操作,但它会在此过程中触发异常, after {{1已执行(在FF和Chrome上测试)。您可以使用greet块来管理例外。

4。作为Getter

@ jehna1有一个完整的答案,所以给他信任。这是一种在全局范围内调用函数无括号的方法,避免使用deprecated __defineGetter__方法。它改为使用Object.defineProperty

我们需要为此创建原始try...catch函数的变体:

greet

然后:

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

greet_get; 替换为您的全局对象。

您可以调用原始的window函数,而不会像这样在全局对象上留下痕迹:

greet

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

5。作为标记功能

使用ES6,您可以使用以下语法调用函数template literal

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

"Tagged Template Literals"

6。作为代理处理程序

在ES6中,您可以定义proxy

greet``;

然后读取任何属性值将调用var proxy = new Proxy({}, { get: greet } );

greet

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

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

答案 1 :(得分:218)

最简单的方法是使用var proxy = new Proxy({}, { has: greet } ); 1 in proxy; // triggers greet 运算符:

&#13;
&#13;
new
&#13;
&#13;
&#13;

虽然这是非正统和不自然的,但它有效且完全合法。

如果没有使用参数,function f() { alert('hello'); } new f;运算符不需要括号。

答案 2 :(得分:91)

您可以使用getter和setter。

self.connection.send(of.ofp_set_config(miss_send_len = 0xFFFD))

使用以下命令运行此脚本:

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

修改

我们甚至可以做参数!

h.ello  // Fires up alert "world"

编辑2:

您还可以定义可以不带括号运行的全局函数:

var h = {
  set ello (what) {
    alert("Hello " + what);
  }
}

h.ello = "world" // Fires up alert "Hello world"

并附带论据:

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

<强>声明:

正如@MonkeyZeus所说:无论你的意图多么好,你都不会在生产中使用这段代码。

答案 3 :(得分:23)

对于特定情况,这是example

window.onload = funcRef;

虽然该声明实际上并非调用,但会导致以后的调用

但是,我认为灰色区域可能适合这样的谜语:)

答案 4 :(得分:15)

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

1。 locationjavascript:协议:

其中一种方法是在javascript:分配上滥用location协议。

工作示例:

&#13;
&#13;
location='javascript:alert\x281\x29'
&#13;
&#13;
&#13;

虽然在评估代码后,技术上 \x28\x29仍然是括号,但实际的()字符不会出现。括号在一串JavaScript中转义,并在分配时进行评估。

2。 onerroreval

同样,根据浏览器的不同,我们可以滥用全局onerror,将其设置为eval,然后抛出将字符串化为有效JavaScript的内容。这个比较棘手,因为浏览器在这种行为上不一致,但这是Chrome的一个例子。

Chrome的工作示例(不是Firefox,其他未经测试):

&#13;
&#13;
window.onerror=eval;Uncaught=0;throw';alert\x281\x29';
&#13;
&#13;
&#13;

这适用于Chrome,因为throw'test'会将'Uncaught test'作为onerror的第一个参数传递,这几乎是有效的JavaScript。如果我们改为throw';test',它将通过'Uncaught ;test'。现在我们有了有效的JavaScript!只需定义Uncaught,并将test替换为有效负载。

结论:

这样的代码真的很糟糕永远不应该使用,但有时会用于XSS攻击,所以故事的寓意不依赖在过滤括号以防止XSS。使用CSP来阻止此类代码也是一个好主意。

答案 5 :(得分:3)

在ES6中,您拥有名为标记模板文字的内容。

例如:

&#13;
&#13;
function foo(val) {
    console.log(val);
}

foo`Tagged Template Literals`;
&#13;
&#13;
&#13;

答案 6 :(得分:1)

用括号调用函数的方法有很多,但我最喜欢的是__defineGetter_

假设您有一个名为 start

的函数
function start(){
   console.log("Starting");
}

通常,defineGetter 在正常使用时会出错。它通常用于

myVariable.__defineGetter__(<name>,<function>);

因为只是

__defineGetter__("Start",start);

会导致错误。所以相反,我使用 window 来做到这一点

window.__defineGetter__("Start",start);

所以现在我们可以使用没有括号的函数了!

Start

控制台:

Starting