Mik*_*uck 260 javascript
今天我被告知可以调用没有括号的函数.我能想到的唯一方法是使用像apply或者这样的函数call.
f.apply(this);
f.call(this);
Run Code Online (Sandbox Code Playgroud)
但这些需要括号apply并将call我们留在第一个方位.我还考虑了将函数传递给某种事件处理程序的想法,例如setTimeout:
setTimeout(f, 500);
Run Code Online (Sandbox Code Playgroud)
但问题就变成了"你如何在setTimeout没有括号的情况下调用它?"
那么这个谜语的解决方案是什么?如何在不使用括号的情况下在Javascript中调用函数?
tri*_*cot 400
调用没有括号的函数有几种不同的方法.
我们假设你定义了这个函数:
function greet() {
console.log('hello');
}
Run Code Online (Sandbox Code Playgroud)
然后在这里按照一些方法调用greet没有括号:
有了new你可以调用一个函数不使用括号:
new greet; // parentheses are optional in this construct.
Run Code Online (Sandbox Code Playgroud)
来自MDN的new鸦片:
句法
Run Code Online (Sandbox Code Playgroud)new constructor[([arguments])]
toString或valueOf实施toString并且valueOf是特殊方法:当需要转换时,它们会被隐式调用:
var obj = {
toString: function() {
return 'hello';
}
}
'' + obj; // concatenation forces cast to string and call to toString.
Run Code Online (Sandbox Code Playgroud)
你可以(ab)使用这个模式来调用greet没有括号:
'' + { toString: greet };
Run Code Online (Sandbox Code Playgroud)
或者valueOf:
+{ valueOf: greet };
Run Code Online (Sandbox Code Playgroud)
valueOf函数原型您可以采用先前的想法覆盖原型valueOf上的方法:Function
Function.prototype.valueOf = function() {
this.call(this);
// Optional improvement: avoid `NaN` issues when used in expressions.
return 0;
};
Run Code Online (Sandbox Code Playgroud)
完成后,您可以写:
+greet;
Run Code Online (Sandbox Code Playgroud)
虽然在线下有括号,但实际的触发调用没有括号.在博客"使用JavaScript调用方法,而不是真正调用它们"中查看更多相关信息
您可以定义一个生成器函数(with *),它返回一个迭代器.您可以使用扩展语法或语法来调用它for...of.
首先,我们需要原始greet函数的生成器变体:
function* greet_gen() {
console.log('hello');
}
Run Code Online (Sandbox Code Playgroud)
然后我们称之为没有括号:
[...{ [Symbol.iterator]: greet_gen }];
Run Code Online (Sandbox Code Playgroud)
通常情况下,生成器会在yield某处使用关键字,但调用该函数不需要它.
最后一个语句调用该函数,但也可以通过解构来完成:
[,] = { [Symbol.iterator]: greet_gen };
Run Code Online (Sandbox Code Playgroud)
或for ... of构造,但它有自己的括号:
for ({} of { [Symbol.iterator]: greet_gen });
Run Code Online (Sandbox Code Playgroud)
请注意,您也可以使用原始greet功能执行上述操作,但在执行完后 greet(在FF和Chrome上测试),它将在此过程中触发异常.您可以使用try...catch块来管理异常.
@ jehna1对此有完整的答案,所以给他信任.这是一种在全局范围内调用函数括号的方法,避免使用不推荐的__defineGetter__方法.它用来Object.defineProperty代替.
我们需要为此创建原始greet函数的变体:
Object.defineProperty(window, 'greet_get', { get: greet });
Run Code Online (Sandbox Code Playgroud)
然后:
greet_get;
Run Code Online (Sandbox Code Playgroud)
替换window为您的全局对象.
您可以调用原始greet函数,而不会像这样在全局对象上留下痕迹:
Object.defineProperty({}, 'greet', { get: greet }).greet;
Run Code Online (Sandbox Code Playgroud)
但有人可能会说我们在这里有括号(虽然他们没有参与实际的调用).
使用ES6,您可以使用以下语法调用函数传递模板文字:
greet``;
Run Code Online (Sandbox Code Playgroud)
请参阅"标记模板文字".
在ES6中,您可以定义代理:
var proxy = new Proxy({}, { get: greet } );
Run Code Online (Sandbox Code Playgroud)
然后读取任何属性值将调用greet:
proxy._; // even if property not defined, it still triggers greet
Run Code Online (Sandbox Code Playgroud)
这有很多变化.还有一个例子:
var proxy = new Proxy({}, { has: greet } );
1 in proxy; // triggers greet
Run Code Online (Sandbox Code Playgroud)
Ami*_*mit 220
最简单的方法是与new运营商:
function f() {
alert('hello');
}
new f;Run Code Online (Sandbox Code Playgroud)
虽然这是非正统和不自然的,但它起作用并且完全合法.
该new如果不使用参数,运营商不需要括号.
jeh*_*na1 93
你可以使用getter和setter.
var h = {
get ello () {
alert("World");
}
}
Run Code Online (Sandbox Code Playgroud)
运行此脚本只需:
h.ello // Fires up alert "world"
Run Code Online (Sandbox Code Playgroud)
编辑:
我们甚至可以做论点!
var h = {
set ello (what) {
alert("Hello " + what);
}
}
h.ello = "world" // Fires up alert "Hello world"
Run Code Online (Sandbox Code Playgroud)
编辑2:
您还可以定义可以不带括号运行的全局函数:
window.__defineGetter__("hello", function() { alert("world"); });
hello; // Fires up alert "world"
Run Code Online (Sandbox Code Playgroud)
并有论据:
window.__defineSetter__("hello", function(what) { alert("Hello " + what); });
hello = "world"; // Fires up alert "Hello world"
Run Code Online (Sandbox Code Playgroud)
免责声明:
正如@MonkeyZeus所说:无论你的意图多么好,你都不会在生产中使用这段代码.
Jon*_*ink 23
以下是特定情况的示例:
window.onload = funcRef;
Run Code Online (Sandbox Code Playgroud)
虽然该语句实际上并未调用,但会导致将来的调用.
但是,我认为灰色区域可能适合这样的谜语:)
Ale*_*ara 15
如果我们接受横向思维方法,那么在浏览器中我们可以滥用几个API来执行任意JavaScript,包括调用函数,而不使用任何实际的括号字符.
location和javascript:协议:一种这样的技术是javascript:在location分配时滥用协议.
工作实例:
location='javascript:alert\x281\x29'Run Code Online (Sandbox Code Playgroud)
虽然在技术上 \x28并且\x29在评估代码后仍然是括号,但实际(和)字符不会出现.括号在一串JavaScript中进行转义,并在赋值时进行评估.
onerror和eval:同样,根据浏览器的不同,我们可以onerror通过设置它来滥用全局eval,并抛出将字符串化为有效JavaScript的内容.这个比较棘手,因为浏览器在这种行为上不一致,但这是Chrome的一个例子.
适用于Chrome的工作示例(不是Firefox,其他未经测试):
window.onerror=eval;Uncaught=0;throw';alert\x281\x29';Run Code Online (Sandbox Code Playgroud)
这适用于Chrome,因为throw'test'它将'Uncaught test'作为第一个参数传递onerror,这几乎是有效的JavaScript.如果我们改为做throw';test',它将通过'Uncaught ;test'.现在我们有了有效的JavaScript!只需定义Uncaught,并用有效负载替换测试.
这样的代码真的很糟糕,永远不应该被使用,但有时会用于XSS攻击,所以故事的寓意是不依赖于过滤括号来阻止XSS.使用CSP来防止这样的代码也是一个好主意.
在 ES6 中,您拥有所谓的Tagged Template Literals。
例如:
function foo(val) {
console.log(val);
}
foo`Tagged Template Literals`;Run Code Online (Sandbox Code Playgroud)