我今天被告知可以调用没有括号的函数。我能想到的唯一方法是使用apply
或call
等功能。
f.apply(this);
f.call(this);
但这些要求在apply
和call
上使用括号,将我们留在第一个方位。我还考虑过将函数传递给某种事件处理程序的想法,例如setTimeout
:
setTimeout(f, 500);
然后问题就变成“你如何在没有括号的情况下调用setTimeout
?”
那么这个谜语的解决方案是什么?如何在不使用括号的情况下在Javascript中调用函数?
答案 0 :(得分:375)
有几种不同的方法来调用没有括号的函数。
我们假设您已定义此功能:
function greet() {
console.log('hello');
}
然后在这里按照一些方法调用greet
而不用括号:
使用new
,您可以调用不带括号的函数:
new greet; // parentheses are optional in this construct.
<强>语法强>
new constructor[([arguments])]
toString
或valueOf
实施 toString
和valueOf
是特殊方法:当需要转换时,它们会被隐式调用:
var obj = {
toString: function() {
return 'hello';
}
}
'' + obj; // concatenation forces cast to string and call to toString.
您可以(ab)使用此模式在没有括号的情况下调用greet
:
'' + { toString: greet };
或valueOf
:
+{ valueOf: greet };
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"
中详细了解相关信息您可以定义generator function(*
),返回iterator。您可以使用spread syntax或for...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
块来管理例外。
@ jehna1有一个完整的答案,所以给他信任。这是一种在全局范围内调用函数无括号的方法,避免使用deprecated __defineGetter__
方法。它改为使用Object.defineProperty
。
我们需要为此创建原始try...catch
函数的变体:
greet
然后:
Object.defineProperty(window, 'greet_get', { get: greet });
将greet_get;
替换为您的全局对象。
您可以调用原始的window
函数,而不会像这样在全局对象上留下痕迹:
greet
但有人可能会说我们在这里有括号(虽然他们没有参与实际的调用)。
使用ES6,您可以使用以下语法调用函数template literal:
Object.defineProperty({}, 'greet', { get: greet }).greet;
在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
运算符:
new
&#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)
答案 4 :(得分:15)
如果我们接受横向思维方法,在浏览器中有几个API,我们可以滥用它来执行任意JavaScript,包括调用函数,而不使用任何实际的括号字符。
location
和javascript:
协议:其中一种方法是在javascript:
分配上滥用location
协议。
工作示例:
location='javascript:alert\x281\x29'
&#13;
虽然在评估代码后,技术上 \x28
和\x29
仍然是括号,但实际的(
和)
字符不会出现。括号在一串JavaScript中转义,并在分配时进行评估。
onerror
和eval
:同样,根据浏览器的不同,我们可以滥用全局onerror
,将其设置为eval
,然后抛出将字符串化为有效JavaScript的内容。这个比较棘手,因为浏览器在这种行为上不一致,但这是Chrome的一个例子。
Chrome的工作示例(不是Firefox,其他未经测试):
window.onerror=eval;Uncaught=0;throw';alert\x281\x29';
&#13;
这适用于Chrome,因为throw'test'
会将'Uncaught test'
作为onerror
的第一个参数传递,这几乎是有效的JavaScript。如果我们改为throw';test'
,它将通过'Uncaught ;test'
。现在我们有了有效的JavaScript!只需定义Uncaught
,并将test替换为有效负载。
这样的代码真的很糟糕,永远不应该使用,但有时会用于XSS攻击,所以故事的寓意不依赖在过滤括号以防止XSS。使用CSP来阻止此类代码也是一个好主意。
答案 5 :(得分:3)
在ES6中,您拥有名为标记模板文字的内容。
例如:
function foo(val) {
console.log(val);
}
foo`Tagged Template Literals`;
&#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