Invoking a function without parentheses
Asked Answered
R

10

338

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?

Ribosome answered 11/3, 2016 at 20:44 Comment(12)
Not trying to be rude, but I must ask: Why?Standardize
@Standardize Because I was answering a question on how functions are invoked and was corrected when I said that they required parentheses on the end.Ribosome
Amazing! I didn't imagine this question would have that much traction.. Perhaps I should have asked it myself :-)Swim
As a practical case, one could imagine being able to inject javascript into some context but they filtered out the () characters.Acima
This is the kind of question that breaks my heart. What good could possibly come through such abuse and exploitation? I want to know one valid use case where <insert any solution> is objectively better or more useful than f().Congressman
@Standardize Because the OP wants Javascript to look like VB6 / VBA / VB.NET? :)Bomber
Keyboard with broken ( and ) keys probably.. or a Lisp hater!Kurtiskurtosis
@naomik There's no valid reason. This whole thread is a "riddle" (and an unhelpful, misleading one IMO).Fpc
@Aaron: you say there’s no valid reason, but, as Alexander O’Mara’s answer points out, one may be considering the question whether removal of brackets is sufficient to prevent code execution — or what about an obfuscated Javascript competition? Of course it is an absurd objective when trying to write maintainable code, but it is an amusing quesetion.Tempestuous
This question was very interesting in researching usage and prevention of XSS techniques.Burdensome
@Aaron, how could you possibly think you know that there's no valid reason? It seems to me that all you can know is that you couldn't think of one. Not surprisingly, your assertion that there's no valid reason is false; see rob's comment about XSS techniques, and the conclusion of Alexander O'Mara's answer. Knowing what's possible and what's not is very important to both attackers and defenders in security.Polymerize
There's no "valid" reason, meaning reasons this might happen are abusive and exploitative or accidental. I maintain that's true, but "valid" was probably a poor word choice: I certainly stand corrected that there are valid reasons to know the answer to this riddle!Fpc
A
543

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])]

2. As toString or valueOf Implementation

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 }

2.b Overriding valueOf in Function Prototype

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(globalThis, 'greet_get', { get: greet });

And then:

greet_get;

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
Artemus answered 11/3, 2016 at 20:47 Comment(29)
That's a very interesting approach using valueOf.Ribosome
Interesting. You can also do: Function.prototype.toString=function(){ this.call(this); return "" };, after which you can also call the function with +funcStandardize
Yep, same principle.Artemus
You forgot about ES6: func``;Shawnshawna
Thanks, @IsmaelMiguel, I have added a paragraph about that. I think the list is hardly complete...Artemus
You're welcome. Something weird you can do is nest calls: func1`${func2`${func3`...`}`}`; The list is hardly complete, but it is the best one so far.Shawnshawna
As I understand the question, the goal is to call a specific (existing) function f. Many of your approaches can be used for that, but not all; and all of them need to be written differently to avoid using parentheses. For example, the toString approach could be written as var greet = { toString: f }; greet + ''; -- or, more tersely, as '' + { toString : f }.Allysonalma
@ruakh, thank you for your comment! the question is indeed open for interpretation in that respect. Anyway I updated my answer a bit taking your comments into account. Thanks!Artemus
Hey, what about the evil eval? eval("setTimeout< function <> { console.log('hello') }, 200 >".replace(/</g , "(").replace(/>/g , ")"))Elemi
You used brackets by calling eval :)Artemus
@Artemus Not anymore: eval`${"setTimeout< function <> { console.log('hello') }, 200 >".replace(/</g , "(").replace(/>/g , ")")}`;Shawnshawna
Yes, but then why use eval? The solution you use now is in the template literal, not in using eval. Just put the target function in its place: greet` `; and you're done (point 5 in my answer).Artemus
Would mentioning the function without parentheses in a return statement also count? E.g. return hello;Aromatize
In that case the function is not executed, but passed to the caller.Artemus
@Artemus Another method will be possible soon with pipeline operator: '1' |> alertIdiomatic
Interesting, @reski! Curious if that will make it to a future ES release.Artemus
this thread is incredible, I was super confused when I saw the func``; syntax for the first timeNucleolar
I like this a lot "Object.defineProperty({}, 'greet', { get: greet }).greet;" but is it possible to define a new statement so I could write "greet 'myself'" and get "Hello myself" as a result? a property does not have arguments.. but maybe there is another wayCalif
@Zibri, that is possible with a template tag function: greet`myself`;Artemus
I know but I was asking a different thing... like "greet myself" without `Calif
@Zibri, not like that, but one can imagine assigning "myself" to a property/variable and that the greet function would be designed to read it.Artemus
I could even do it in this way: Object.defineProperty(window, 'newcmd', { set: (arg)=>console.log(arg) }) newcmd = "hello"Calif
what I mean is something like the "let" statement.Calif
If you find something interesting in that way, post it as an answer ;-) Or ask a new question about it.Artemus
I was trying to understand how the styled function in emotion emotion.sh/docs/introduction was implemented. your answer helped me find the tagged templates. Thanks!Lumberman
In what version of JavaScript did they make it so that you can instantiate an object using the "new" operator without parentheses? MDN makes no mention of it.Muticous
@PHPGuru, it has always been like that. See for example the EcmaScript 3 specification in section 11.2.2, where the expression after new can evaluate to a constructor. MDN shows this in its syntax description (square brackets mean that something is optional).Artemus
@Artemus Thank you for linking to a source. I had been trying to find one that shows support dating back to the early days of JavaScript, and that one is perfect.Muticous
fwiw, Prisma uses the aforementioned Tagged Template Literals for functions like $queryRaw(). This clever approach enables Prisma to "[create] prepared statements that are safe from SQL injections". (Prisma Docs)Millihenry
S
227

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.

Swim answered 11/3, 2016 at 20:47 Comment(4)
Correction, the easiest way to do this is to prepend an operand that forces the function expression to be evaluated. !f results in the same thing, without instantiating an instance of the constructor function (which requires creating a new this context). It's much more performant and is used in many popular libraries (like Bootstrap).Rostellum
@Rostellum - evaluating an expression is not the same as executing a function, but if you have a different (nicer? more surprising?) method of invoking (causing execution) of a function - post an answer!Swim
The point of prepending an exclamation mark, or any other single character unary operator (+, -, ~) in such libraries, is to save a byte in the minimized version of the library where the return value isn't needed. (i.e. !function(){}()) The usual self-calling syntax is (function(){})() (unfortunately the syntax function(){}() isn't cross-browser) Since the top-most self-calling function usually has nothing to return, it's usually the target of this byte saving techniqueDistend
@Rostellum Does this hold true? I just tried it in Chrome, and wasn't getting function execution. function foo() { alert("Foo!") }; For example: !foo returns falseCompetent
S
107

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.

Standardize answered 11/3, 2016 at 20:51 Comment(8)
Strictly speaking from the POV of "I'm an axe wielding mad-man that has the honor of taking over your code because you've moved on to bigger and better things; yet I know where you live". I really hope this isn't normal lol. Using it inside of a plug-in which you maintain, acceptable. Writing business-logic code, please hold while I sharpen my axe :)Morphogenesis
@Morphogenesis haha, yes! Added a disclaimer for coders of the future that can find this from GoogleStandardize
Actually this disclaimer is too harsh. There are legitimate use cases for "getter as a function call". In fact it's used extensively in a very successful library. (would you like a hint?? :-)Swim
Note that __defineGetter__ is deprecated. Use Object.defineProperty instead.Cholecystotomy
@Swim According to my comment, using it in your library is acceptable. I presume it's not used in business-logic code which can easily be passed off to less skilled programmers as attrition and re-hiring occurs?Morphogenesis
@Morphogenesis - as I explicitly wrote in the comment - this style of function invocation is being used, extensively & intentionally, in a very successful public library as the API itself, not internally.Swim
@Swim Which one?Roath
The disclaimer almost look like a That looks like a Tagged Template Literal use caseKeverne
N
26

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 :)

Not answered 11/3, 2016 at 20:46 Comment(10)
That's nice but that's not JavaScript, it's DOM.Swim
@Amit, the DOM is part of the browser's JS environment, which is still JavaScript.Conservatory
@Conservatory Not all ECMAScript runs in a web browser. Or are you among the people who use "JavaScript" to refer specifically to combining ES with the HTML DOM, as opposed to Node?Silviasilviculture
@DamianYerrick, I consider the DOM to be a library available in some JS environments, which doesn't make it any less JavaScript than underscore being available in some environments. It's still JavaScript, it's just not a part that's specced in the ECMAScript specification.Conservatory
@zzzzBov, "Although the DOM is often accessed using JavaScript, it is not a part of the JavaScript language. It can also be accessed by other languages.". For example, FireFox uses XPIDL and XPCOM for DOM implementation. It is not so self-evident that the call of your specified callback function is implemented in JavaScript. The DOM is not an API like other JavaScript libraries.Artemus
@trincot, I agree with everything up to "The DOM is not an API like other JavaScript libraries" because that's wrong. Even the title of the page you linked to disproves it: "Document Object Model (DOM) - Web APIs | MDN" The DOM is an API, its implementation may not be in JavaScript, but that more than solidifies the point that this answer is making in that the function can be executed without requiring parenthesis.Conservatory
@zzzzBov, indeed the DOM is an API, I didn't claim it wasn't. But it is not an API like other JavaScript libraries, in the sense that it would be pure JavaScript. And yes, this might show that the function can be invoked without parentheses, it is just that it is the DOM that invokes it, while the OP asked How can you invoke a function in Javascript. But I will not insist, this is probably a case of varying interpretations.Artemus
@Conservatory I guess you are saying you can invoke your JavaScript function from native code, that's a stretch;) It's a stretch to call the DOM JavaScript, it can call JavaScript, but it's not JavaScript.Veradia
@JuanMendes, why is it a stretch to call the DOM API JavaScript? Is it as much of a stretch to call the fs node API JavaScript? It's an API...for JavaScript. If you only count functions listed in the ECMAScript spec as "JavaScript" you'll find yourself with a language that can't do much at all.Conservatory
that is a normal Object setter... and can be done easily Object.defineProperty(window, 'newcmd', { set: (arg)=>console.log(arg) }) newcmd = "hello"Calif
T
20

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.

1. location and javascript: protocol:

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.


2. onerror and eval:

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.

Tonry answered 14/3, 2016 at 8:0 Comment(6)
Isn't this the same as using eval and writing the string without actually using the parentheses characters.Bomber
@ZenSpitz Yep, but eval normally requires parentheses, hence this filter evasion hack.Ranjiv
Arguably \x28 and \x29 are still parentheses. '\x28' === '('.Artemus
@Artemus Which is kind-of the point I covered in the answer, this is a lateral thinking approach which showcases a reason for which in which this might be done. I've made it more clear in the answer.Ranjiv
Also, whoever voted to delete this, please review the guidelines for deleting answers.Ranjiv
Letting the URL decoder do its work allows to use an escape mechanism other than javascript string literal's, location='javascript:alert%281%29'Gaffe
H
7

In ES6, you have what's called Tagged Template Literals.

For example:

function foo(val) {
    console.log(val);
}

foo`Tagged Template Literals`;
Heterozygote answered 27/10, 2017 at 16:48 Comment(3)
Indeed, this is in the answer I posted 1.5 years before yours... not sure why it deserves a new answer?Artemus
because some other people, who want to implement the same thing right now can use the new answer.Sumatra
@mehta-rohan, I don't understand that comment. If this would make sense then why not duplicate the same answer over and over gain? I can't see how that would be useful.Artemus
C
3

We can use the Function class, which you can use to build a function from a string like so:

let x = Function("alert(123)");
// To invoke the function
x();

As the question specifies, we are not allowed to use "(" and ")", so we can instead do the following for the inner function we want to invoke:

let x = Function("alert\x28123\x29");

This works because JS allows to specify characters using hex represention inside a string.

Now we are left with the parentheses of the constructor and invocation.

JS allow us to invoke a function with "``" instead of "()".

let x = Function`alert\x28123\x29`;
x``;

All together:

Function`alert\x28123\x29```

And you can even get a reference to the Function class without directly calling it:

Array.constructor`alert\x28"invoke with whatever u want"\x29```;

As <any-class>.constructor is a Function object. When Function objects are invoked, they return a function which it's body is the arguments it got.

Construe answered 2/11, 2022 at 18:30 Comment(3)
While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. You can find more information on how to write good answers in the help center: stackoverflow.com/help/how-to-answer . Good luckMinuteman
Why did you reference the Function object with Array.constructor and not as ... Function?Artemus
Both works, wanted to give as an example something less well known.Construe
B
1

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);
Besmear answered 14/4, 2022 at 11:33 Comment(3)
There are a lot of parentheses here...Artemus
Please check again, the one function passed as argument in then() method without parenthesisBesmear
Yes, which confirms you need parentheses to get the function called. Note how the asker already proposed such constructs, but with apply and call and then writes "But these require parentheses on apply and call leaving us at square one.". So also your answer brings us to square one.Artemus
C
0

Updated answer You can invoke a function (run js code) without parenthesis, while passing parameters This is a bit of a hack, but it definitly works To do it, you need a class or Object.defineProperty. Here's the class example:

class RunJs {
    static set funcName(params){
         // Code to run. Note, to pass multiple params, use an array.
    }
}
// To run it
RunJS.funcName = ["param1", "param2", "etc"];

When you call the function, you are using no parenthesis, and it runs code and can take parameters.

For an object, use Object.defineProperty

const obj = {
    thisCanBeAnthing:"and this"
};
Object.defineProperty(obj, "thisCanBeAnything", {
    set(params){
        // code to run
    }
});
And to call it: 
obj.thisCanBeAnthing = "param"; // Or an array of parameters.

When you call it, no parenthesis are used.

Clotilda answered 20/5, 2023 at 6:42 Comment(0)
C
-1

You can use an anonymous function. It only works using pre-ES6 syntax, but still, it works.

Code:

//ES6+ (using const, still not using arrow functions)
const myFunc = (function(args){console.log("no parenthesis")})(args);

and invoke it like this:

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

Before ES6:

var myNonES6Func = (function(args){console.log("Use var before ES6.")})(args);

and invoke it like this

myNonES6Func;
// ^^^ same as the ES6 invocation.

const es6_func = (function() {
    alert("ES6!")
})();
var before_es6_func = (function() {
    alert("Before ES6.")
})();
const es6 = () => {
    es6_func
}

function before_es6() {
    before_es6_func
}
<button onclick="es6">ES6+</button>
<button onclick="before_es6">Before ES6</button>
NOTE: Modern browsers do not seem to have this functionality anymore (it calls itself on page load, but when you called it normally, it would also work but you would have to add some counting code to keep it from running on page load) I did test it on Internet Explorer 11, and it seems to still work though, but Chrome, Firefox, and Edge do not work, it might've just been a bug in IE.**
Clotilda answered 14/9, 2022 at 0:16 Comment(2)
No, this doesn't work like you described, and never has. What you have there is an IIFE, and it runs immediately -- because of the parentheses! --, not when you put the name of the function as a separate statement.Artemus
True, and I totally missed that. At the time I posted this (over a year ago) I was just getting into javascript so maybe I shouldnt've posted the answer, but anyway, thanks for catching that!Clotilda

© 2022 - 2024 — McMap. All rights reserved.