Invoking a function without parentheses
JavascriptJavascript Problem Overview
I was told today that it's possible to invoke a function without parentheses. The only ways I could think of was using functions like apply
or call
.
f.apply(this);
f.call(this);
But these require parentheses on apply
and call
leaving us at square one. I also considered the idea of passing the function to some sort of event handler such as setTimeout
:
setTimeout(f, 500);
But then the question becomes "how do you invoke setTimeout
without parentheses?"
So what's the solution to this riddle? How can you invoke a function in Javascript without using parentheses?
Javascript Solutions
Solution 1 - Javascript
There are several different ways to call a function without parentheses.
Let's assume you have this function defined:
function greet() {
console.log('hello');
}
Then here follow some ways to call greet
without parentheses:
1. As Constructor
With new
you can invoke a function without parentheses:
new greet; // parentheses are optional in this construct.
From MDN on the new
oprator:
> Syntax > > new constructor[([arguments])]
toString
or valueOf
Implementation
2. As toString
and valueOf
are special methods: they get called implicitly when a conversion is necessary:
var obj = {
toString: function() {
return 'hello';
}
}
'' + obj; // concatenation forces cast to string and call to toString.
You could (ab)use this pattern to call greet
without parentheses:
'' + { toString: greet };
Or with valueOf
:
+{ valueOf: greet };
valueOf
and toString
are in fact called from the @@toPrimitive method (since ES6), and so you can also implement that method:
+{ [Symbol.toPrimitive]: greet }
"" + { [Symbol.toPrimitive]: greet }
valueOf
in Function Prototype
2.b Overriding You could take the previous idea to override the valueOf
method on the Function
prototype:
Function.prototype.valueOf = function() {
this.call(this);
// Optional improvement: avoid `NaN` issues when used in expressions.
return 0;
};
Once you have done that, you can write:
+greet;
And although there are parentheses involved down the line, the actual triggering invocation has no parentheses. See more about this in the blog "Calling methods in JavaScript, without really calling them"
3. As Generator
You could define a generator function (with *
), which returns an iterator. You can call it using the spread syntax or with the for...of
syntax.
First we need a generator variant of the original greet
function:
function* greet_gen() {
console.log('hello');
}
And then we call it without parentheses by defining the @@iterator method:
[...{ [Symbol.iterator]: greet_gen }];
Normally generators would have a yield
keyword somewhere, but it is not needed for the function to get called.
The last statement invokes the function, but that could also be done with destructuring:
[,] = { [Symbol.iterator]: greet_gen };
or a for ... of
construct, but it has parentheses of its own:
for ({} of { [Symbol.iterator]: greet_gen });
Note that you can do the above with the original greet
function as well, but it will trigger an exception in the process, after greet
has been executed (tested on FF and Chrome). You could manage the exception with a try...catch
block.
4. As Getter
@jehna1 has a full answer on this, so give him credit. Here is a way to call a function parentheses-less on the global scope, avoiding the deprecated __defineGetter__
method. It uses Object.defineProperty
instead.
We need to create a variant of the original greet
function for this:
Object.defineProperty(window, 'greet_get', { get: greet });
And then:
greet_get;
Replace window
with whatever your global object is.
You could call the original greet
function without leaving a trace on the global object like this:
Object.defineProperty({}, 'greet', { get: greet }).greet;
But one could argue we do have parentheses here (although they are not involved in the actual invocation).
5. As Tag Function
Since ES6 you can call a function passing it a template literal with this syntax:
greet``;
See "Tagged Template Literals".
6. As Proxy Handler
Since ES6, you can define a proxy:
var proxy = new Proxy({}, { get: greet } );
And then reading any property value will invoke greet
:
proxy._; // even if property not defined, it still triggers greet
There are many variations of this. One more example:
var proxy = new Proxy({}, { has: greet } );
1 in proxy; // triggers greet
7. As instance checker
The instanceof
operator executes the @@hasInstance
method on the second operand, when defined:
1 instanceof { [Symbol.hasInstance]: greet } // triggers greet
Solution 2 - Javascript
The easiest way to do that is with the new
operator:
function f() {
alert('hello');
}
new f;
While that's unorthodox and unnatural, it works and is perfectly legal.
The new
operator doesn't require parentheses if no parameters are used.
Solution 3 - Javascript
You can use getters and setters.
var h = {
get ello () {
alert("World");
}
}
Run this script just with:
h.ello // Fires up alert "world"
Edit:
We can even do arguments!
var h = {
set ello (what) {
alert("Hello " + what);
}
}
h.ello = "world" // Fires up alert "Hello world"
Edit 2:
You can also define global functions that can be run without parenthesis:
window.__defineGetter__("hello", function() { alert("world"); });
hello; // Fires up alert "world"
And with arguments:
window.__defineSetter__("hello", function(what) { alert("Hello " + what); });
hello = "world"; // Fires up alert "Hello world"
Disclaimer:
As @MonkeyZeus stated: Never ever shall you use this piece of code in production, no matter how good your intentions.
Solution 4 - Javascript
Here's an example for a particular situation:
window.onload = funcRef;
Although that statement is not actually invoking but will lead to a future invocation.
But, I figure grey-areas might be ok for riddles like this :)
Solution 5 - Javascript
If we accept a lateral thinking approach, in a browser there are several API's we can abuse to execute arbitrary JavaScript, including calling a function, without any actual parenthesis characters.
location
and javascript:
protocol:
1. One such technique is to abuse the javascript:
protocol on location
assignment.
Working Example:
location='javascript:alert\x281\x29'
Although technically \x28
and \x29
are still parenthesis once the code is evaluated, the actual (
and )
character does not appear. The parentheses are escaped in a string of JavaScript which gets evaluated on assignment.
onerror
and eval
:
2. Similarly, depending on the browser we can abuse the global onerror
, by setting it to eval
, and throwing something that will stringify to valid JavaScript. This one is trickier, because browsers are inconsistent in this behavior, but here's an example for Chrome.
Working example for Chrome (not Firefox, others untested):
window.onerror=eval;Uncaught=0;throw';alert\x281\x29';
This works in Chrome because throw'test'
will pass 'Uncaught test'
as the first argument to onerror
, which is almost valid JavaScript. If we instead do throw';test'
it will pass 'Uncaught ;test'
. Now we have valid JavaScript! Just define Uncaught
, and replace test with the payload.
In conclusion:
Such code is truly awful, and should never be used, but is sometimes used in XSS attacks, so the moral of the story is don't rely on filtering parenthesis to prevent XSS. Using a CSP to prevent such code would also be a good idea.
Solution 6 - Javascript
In ES6, you have what's called Tagged Template Literals.
For example:
function foo(val) {
console.log(val);
}
foo`Tagged Template Literals`;
Solution 7 - Javascript
Here is another example where I am passing function one in then function without parantheses and it is called.
function one() {
console.log("one called");
}
function two() {
return new Promise((resolve, reject) => {
resolve();
});
}
two().then(one);