今天有人告诉我,没有括号也可以调用函数。我能想到的唯一方法是使用apply或call这样的函数。
f.apply(this);
f.call(this);
但是这些需要在apply和call上加上括号,让我们回到原点。我还考虑了将函数传递给某种事件处理程序,如setTimeout:
setTimeout(f, 500);
但问题就变成了“如何在没有括号的情况下调用setTimeout ?”
那么这个谜语的答案是什么呢?如何在Javascript中调用函数而不使用括号?
今天有人告诉我,没有括号也可以调用函数。我能想到的唯一方法是使用apply或call这样的函数。
f.apply(this);
f.call(this);
但是这些需要在apply和call上加上括号,让我们回到原点。我还考虑了将函数传递给某种事件处理程序,如setTimeout:
setTimeout(f, 500);
但问题就变成了“如何在没有括号的情况下调用setTimeout ?”
那么这个谜语的答案是什么呢?如何在Javascript中调用函数而不使用括号?
当前回答
最简单的方法是使用new操作符:
函数f() { alert('你好'); } 新的f;
虽然这是不正统和不自然的,但它是有效的,是完全合法的。
如果不使用参数,new操作符不需要括号。
其他回答
你可以使用getter和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所说:永远不要在生产中使用这段代码,不管你的意图有多好。
如果我们接受横向思维方法,在浏览器中,我们可以滥用多个API来执行任意JavaScript,包括调用函数,而不需要任何实际的括号字符。
1. 位置和javascript:协议:
其中一种技术就是在位置分配上滥用javascript:协议。
工作的例子:
地方= ' javascript: alert x281喝x29”
虽然技术上\x28和\x29在代码求值时仍然是括号,但实际的(和)字符不会出现。括号在JavaScript字符串中转义,在赋值时求值。
2. Onerror和eval:
类似地,根据浏览器的不同,我们可以滥用全局onerror,将其设置为eval,并抛出一些将字符串化为有效JavaScript的东西。这一点比较棘手,因为浏览器在这个行为上是不一致的,但这里有一个Chrome的例子。
Chrome的工作示例(不是Firefox,其他未经测试):
window.onerror = eval;未捕获= 0;抛出“;警报\ x281 \ x29”;
这在Chrome中工作,因为throw'test'将通过'Uncaught test'作为onerror的第一个参数,这几乎是有效的JavaScript。如果我们抛出';test',它会通过'Uncaught;test'。现在我们有了有效的JavaScript!只需定义Uncaught,并将test替换为有效负载。
结论:
这样的代码确实很糟糕,永远不应该使用,但有时会用于XSS攻击,所以这个故事的寓意是不要依赖过滤括号来防止XSS。使用CSP来防止这样的代码也是一个好主意。
下面是一个特定情况的例子:
window.onload = funcRef;
尽管该语句实际上没有调用,但将导致未来的调用。
但是,我认为灰色区域对于这样的谜语来说是可以的:)
在ES6中,你有所谓的标记模板文字。
例如:
函数foo(val) { console.log (val); } foo '标记模板文字';
可以使用匿名函数。 它只能使用es6之前的语法,但仍然可以工作。
代码:
//ES6+ (using const, still not using arrow functions)
const myFunc = (function(args){console.log("no parenthesis")})(args);
然后像这样调用它:
myFunc;
// ^^^ no parenthesis in invocation, but you do have parenthesis in definition
// also note that the semicolon is optional if it is the only thing on the line
ES6之前:
var myNonES6Func = (function(args){console.log("Use var before ES6.")})(args);
像这样调用它
myNonES6Func;
// ^^^ same as the ES6 invocation.
有趣的事情发生了。 警报(ES6 !”) }) (); var before_es6_func = (function) 警报(ES6之前”。) }) (); const es6 = () => es6_func 的 有趣的前_es6() before_es6_func 的 <按钮onclick = >“es6巴顿es6 + < - > <按钮onclick="before_es6">Before ES6</按钮>
注意:现代浏览器似乎不再有这个功能了(它在页面加载时调用自己,但当你正常调用它时,它也可以工作,但你必须添加一些计数代码来防止它在页面加载时运行)我在Internet Explorer 11上测试了它,它似乎仍然可以工作,但Chrome, Firefox和Edge不能工作,这可能只是IE中的一个bug。