Indirect function call in JavaScript - javascript

There are things like
f.call(...)
f.apply(...)
But then there's this
(1, alert)('Zomg what is this????!!!11')
"1" does not seem to mean much in this context, the following works just fine:
(null, alert)('Zomg what is this????!!!11')
(1, null, alert)('Zomg what is this????!!!11')
(undefined, alert)('Zomg what is this????!!!11')
Could you point to a specific part of ECMAScript which describes that syntax?

You are just using The Comma Operator.
This operator only evaluates its operands from left to right, and returns the value from the second one, for example:
(0, 1); // 1
('foo', 'bar'); // 'bar'
In the context of calling a function, the evaluation of the operand will simply get a value, not a reference, this causes that the this value inside the invoked function point to the global object (or it will be undefined in the new ECMAScript 5 Strict Mode).
For example:
var foo = 'global.foo';
var obj = {
foo: 'obj.foo',
method: function () {
return this.foo;
}
};
obj.method(); // "obj.foo"
(1, obj.method)(); // "global.foo"
As you can see, the first call, which is a direct call, the this value inside the method will properly refer to obj (returning "obj.foo"), the second call, the evaluation made by the comma operator will make the this value to point to the global object (yielding "global.foo").
That pattern has been getting quite popular these days, to make indirect calls to eval, this can be useful under ES5 strict mode, to get a reference to the global object, for example, (imagine you are in a non-browser environment, window is not available):
(function () {
"use strict";
var global = (function () { return this || (1,eval)("this"); })();
})();
In the above code, the inner anonymous function will execute within a strict mode code unit, that will result on having the this value as undefined.
The || operator will now take the second operand, the eval call, which is an indirect call, and it will evaluate the code on the global lexical and variable environment.
But personally, in this case, under strict mode I prefer using the Function constructor to get the global object:
(function () {
"use strict";
var global = Function('return this')();
})();
Functions that are created with the Function constructor are strict only if they start with a Use Strict Directive, they don't "inherit" the strictness of the current context as Function Declarations or Function Expressions do.

It's the comma operator, which evaluates both of its operands and returns the value of the second one.
So, something like (null, alert) evaluates to the alert function, which you can immediately call using parentheses.
It's described in section 11.14 of ECMA-262 (PDF).

The comma operator causes expressions to be evaluated sequentially. Wrapping the expressions in parentheses returns the value of the last expression. So (1, alert)("hello") is functionally equivalent to:
1;
alert("hello");
Off the top of my head, I can't think of a reason to do this.

Related

Why is the named IIFE logged instead of the variable with the same name?

I saw the code below that someone posted. I’m confused about what it logs. It logs the function a, not 200. Why?
var a = 1;
(function a() {
a = 200;
console.log(a)
})()
Because the function being immediately invoked is named, and that name cannot be reassigned to refer to something else directly inside the IIFE.
Any named function expressions will exhibit this behavior as well. A function expression whose function is named a will mean that a directly inside the function will always refer to the function itself, even if you try to reassign it.
You can make the error explicit if you use strict mode:
'use strict';
var a = 1;
(function a() {
a = 200;
console.log(a)
})()
Uncaught TypeError: Assignment to constant variable.
Having a named function expression is a bit like having
(function a() {
const a = <this function>;
// ...
})()
except trying to reassign it will only throw in strict mode.
Specifically, I believe the ECMAScript 5 specification for this behavior is in SetMutableBinding:
If the binding for N in envRec is a mutable binding, change its bound value to V.
Else this must be an attempt to change the value of an immutable binding so if S (strict mode being used) if true throw a TypeError exception.
But directly inside a function, the function name binding is not mutable - see Function Definition:
The production
FunctionExpression : function Identifier ( FormalParameterListopt ) { FunctionBody }
is evaluated as follows:
Call the CreateImmutableBinding concrete method of envRec, passing the String value of Identifier as the argument.

Why wrap `eval` like this `(0, eval)`? [duplicate]

I start to read JavaScript Patterns, some codes confused me.
var global = (function () {
return this || (1, eval)('this');
}());
Here are my questions:
Q1:
(1, eval) === eval?
Why and how does it work?
Q2: Why not just
var global = (function () {
return this || eval('this');
}());
or
var global = (function () {
return this;
}());
The difference between (1,eval) and plain old eval is that the former is a value and the latter is an lvalue. It would be more obvious if it were some other identifier:
var x;
x = 1;
(1, x) = 1; // syntax error, of course!
That is (1,eval) is an expression that yields eval (just as say, (true && eval) or (0 ? 0 : eval) would), but it's not a reference to eval.
Why do you care?
Well, the Ecma spec considers a reference to eval to be a "direct eval call", but an expression that merely yields eval to be an indirect one -- and indirect eval calls are guaranteed to execute in global scope.
Things I still don't know:
Under what circumstance does a direct eval call not execute in global scope?
Under what circumstance can the this of a function at global scope not yield the global object?
Some more information can be gleaned here.
EDIT
Apparently, the answer to my first question is, "almost always". A direct eval executes from the current scope. Consider the following code:
var x = 'outer';
(function() {
var x = 'inner';
eval('console.log("direct call: " + x)');
(1,eval)('console.log("indirect call: " + x)');
})();
Not surprisingly (heh-heh), this prints out:
direct call: inner
indirect call: outer
EDIT
After more experimentation, I'm going to provisionally say that this cannot be set to null or undefined. It can be set to other falsy values (0, '', NaN, false), but only very deliberately.
I'm going to say your source is suffering from a mild and reversible cranio-rectal inversion and might want to consider spending a week programming in Haskell.
The fragment
var global = (function () {
return this || (1, eval)('this');
}());
will correctly evaluate to the global object even in strict mode. In non-strict mode the value of this is the global object but in strict mode it is undefined. The expression (1, eval)('this') will always be the global object.
The reason for this involves the rules around indirect versus direct eval. Direct calls to eval has the scope of the caller and the string this would evaluate to the value of this in the closure. Indirect evals evaluate in global scope as if they were executed inside a function in the global scope.
Since that function is not itself a strict-mode function the global object is passed in as this and then the expression 'this' evaluates to the global object. The expression (1, eval) is just a fancy way to force the eval to be indirect and return the global object.
A1: (1, eval)('this') is not the same as eval('this') because of the special rules around indirect versus direct calls to eval.
A2: The original works in strict mode, the modified versions do not.
To Q1:
I think this is a good example of comma operator in JS. I like the explanation for comma operator in this article: http://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/
The comma operator evaluates both of its operands (from left to right) and returns the value of the second operand.
To Q2:
(1, eval)('this') is considered as indirect eval call, which in ES5 does execute code globally. So the result will be the global the context.
See http://perfectionkills.com/global-eval-what-are-the-options/#evaling_in_global_scope
Q1: Multiple consecutive javascript statements separated by a comma take the value of the last statement. So:
(1, eval) takes the value of the last one which is a function reference to the eval() function. It apparently does it this way to make the eval() call into an indirect eval call that will be evaluated in the global scope in ES5. Details explained here.
Q2: There must be some environment that doesn't define a global this, but does define eval('this'). That's the only reason I can think of for that.

eval(fn) and eval(arrowFn) returns different value

As per the Mozilla docs in order to execute a function using eval it must be wrapped inside ( ) i.e. if you don't use them then it treated as a string.
eval as a string defining function requires "(" and ")" as prefix and suffix
when I execute normal function it returns undefined as expected but not in the case of ES6 functions. My Question is ES6 functions are treated differently by javascript engines or only within eval function.
var fn = "function a(){}";
var es6fn = "()=>{}";
console.log(eval(fn)); // undefined
console.log(eval(es6fn)); // ()=>{}
console.log(typeof eval(es6fn)); // ()=>{} i.e. a function
Lets take a step back and see what is actually going on here. I think you are misunderstanding the point MDN is trying to make. The only function that is executed in your example is eval. The (...) the documentation is mentioning are not for executing the function inside the string but for changing how the function definition is evaluated.
A function call would function a(){}() but the docs talk about putting the function definition inside parenthesis: (function(){}).
There are basically thee major ways to define functions:
Function declaration
function foo() {}
Function expression
var foo = function() {}
Arrow function
var foo = () => {}
To understand the difference between a function declaration and a function expression, we have to understand the difference between statements and expressions (a declaration is basically like a statement).
A statement is something that has side effects and does not produce a value. if, for, switch, etc are all statements.
An expression is something that produces a value. E.g. 5 is a number literal that produces the value 5. 5 + 3 is an expression that computes the sum of the two literals, i.e. evaluating it will return the value 8.
A function declaration is like a statement. It doesn't produce a value itself, but as a side effect, a variable is defined whose value is a function (you can see in the specification that nothing happens when a function declaration is evaluated (they have already been processed at that point)).
A function expression is very similar, but instead of defining a variable, evaluating it simply results in the function object.
And that is the reason why
eval('function a() {}') // undefined, but a is defined as side effect
eval('(function a() {})') // a function object
produce different results. The first is interpreted as function declaration. A variable a will be created, but no value is created that eval could return. In the second case, the grouping operator ((...)) forces the function definition to be interpreted as a function expression, which means that a value is produced and return by eval.
Now regarding arrow functions: There is no ambiguity here. Arrow function definitions are always expressions, i.e. evaluating them always produces a value.
eval(`() => {}`) // a function object
To sum up
While there is a difference between arrow functions and function declarations/expressions, this difference is not the reason for the results you are seeing with eval. The difference here is because of evaling a statement/declaration and an expression.
In your example, a is declared as it's a named function. In the second case, you just write an expression which is a lambda function. See here and here.
If you want to get the same effect for fn, do
`console.log(eval("var a = function(){}"))`; //`function(){}`.
First of all, EcmaScript is the "official" name for JavaScript. Now that ES2015 is finalised, it effectively just becomes JavaScript v6 to most people. So, this difference does not come from the different engin.
The origin of the different behavior comes from the result of the string which is written in the eval function. the result of the first eval string is a function definition and there is not anything to return. On the other side, the second eval is evaluating a lambda function, so the result of the eval is that function. To clear this concept, you can rewrite the code like the following:
var fn = "function a(){ return 1;}";
var es6fn = "()=>{}";
console.log(eval(fn)); // undefined
console.log(eval(es6fn)); // ()=>{}
console.log(typeof eval(es6fn)); // ()=>{} i.e. a function
console.log(a()); // call the a() function
As, you can see, the a() is defined as a function, and you can use the function after the first eval. So, the first eval is run and all back to the return value for eval function.
The documentation says nothing on function execution. The functions won't be executed, unless they are executed explicitly like (() => {})().
The quote
eval as a string defining function requires "(" and ")" as prefix and suffix
refers to interpreting the string as function expression rather than function declaration.
// will throw SyntaxError
// because function declaration requires a name
typeof eval('function (){}');
typeof eval('function a(){}') === 'undefined';
typeof eval('(function a(){})') === 'function';
typeof eval('null, function a(){}') === 'function';
typeof eval('()=>{}') === 'function';
Arrow function is always an expression, it doesn't need auxiliary constructions like comma or parentheses to interpret is an expression, here is the difference.

Access global object without hard-coding 'window' [duplicate]

I start to read JavaScript Patterns, some codes confused me.
var global = (function () {
return this || (1, eval)('this');
}());
Here are my questions:
Q1:
(1, eval) === eval?
Why and how does it work?
Q2: Why not just
var global = (function () {
return this || eval('this');
}());
or
var global = (function () {
return this;
}());
The difference between (1,eval) and plain old eval is that the former is a value and the latter is an lvalue. It would be more obvious if it were some other identifier:
var x;
x = 1;
(1, x) = 1; // syntax error, of course!
That is (1,eval) is an expression that yields eval (just as say, (true && eval) or (0 ? 0 : eval) would), but it's not a reference to eval.
Why do you care?
Well, the Ecma spec considers a reference to eval to be a "direct eval call", but an expression that merely yields eval to be an indirect one -- and indirect eval calls are guaranteed to execute in global scope.
Things I still don't know:
Under what circumstance does a direct eval call not execute in global scope?
Under what circumstance can the this of a function at global scope not yield the global object?
Some more information can be gleaned here.
EDIT
Apparently, the answer to my first question is, "almost always". A direct eval executes from the current scope. Consider the following code:
var x = 'outer';
(function() {
var x = 'inner';
eval('console.log("direct call: " + x)');
(1,eval)('console.log("indirect call: " + x)');
})();
Not surprisingly (heh-heh), this prints out:
direct call: inner
indirect call: outer
EDIT
After more experimentation, I'm going to provisionally say that this cannot be set to null or undefined. It can be set to other falsy values (0, '', NaN, false), but only very deliberately.
I'm going to say your source is suffering from a mild and reversible cranio-rectal inversion and might want to consider spending a week programming in Haskell.
The fragment
var global = (function () {
return this || (1, eval)('this');
}());
will correctly evaluate to the global object even in strict mode. In non-strict mode the value of this is the global object but in strict mode it is undefined. The expression (1, eval)('this') will always be the global object.
The reason for this involves the rules around indirect versus direct eval. Direct calls to eval has the scope of the caller and the string this would evaluate to the value of this in the closure. Indirect evals evaluate in global scope as if they were executed inside a function in the global scope.
Since that function is not itself a strict-mode function the global object is passed in as this and then the expression 'this' evaluates to the global object. The expression (1, eval) is just a fancy way to force the eval to be indirect and return the global object.
A1: (1, eval)('this') is not the same as eval('this') because of the special rules around indirect versus direct calls to eval.
A2: The original works in strict mode, the modified versions do not.
To Q1:
I think this is a good example of comma operator in JS. I like the explanation for comma operator in this article: http://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/
The comma operator evaluates both of its operands (from left to right) and returns the value of the second operand.
To Q2:
(1, eval)('this') is considered as indirect eval call, which in ES5 does execute code globally. So the result will be the global the context.
See http://perfectionkills.com/global-eval-what-are-the-options/#evaling_in_global_scope
Q1: Multiple consecutive javascript statements separated by a comma take the value of the last statement. So:
(1, eval) takes the value of the last one which is a function reference to the eval() function. It apparently does it this way to make the eval() call into an indirect eval call that will be evaluated in the global scope in ES5. Details explained here.
Q2: There must be some environment that doesn't define a global this, but does define eval('this'). That's the only reason I can think of for that.

I don't understand why the value of an expression comparing two functions using === is false

This is my code:
var emptyFunction = function () {};
console.log(emptyFunction === function () {});
This will log false in the console. Why?
Because the function expression, when executed, produces a new function object.
=== returns true only if the two operands are the same object.
From the spec (emphasis mine):
The production FunctionExpression : function ( FormalParameterListopt ) { FunctionBody }
is evaluated as follows:
1. Return the result of creating a new Function object as specified in 13.2 with parameters specified by
FormalParameterListopt and body specified by FunctionBody. Pass in the LexicalEnvironment of the running
execution context as the Scope. Pass in true as the Strict flag if the FunctionExpression is contained in strict code or
if its FunctionBody is strict code.
Because
function(){}
is an anonymous function "instance".
So you set emptyFunction to one instance of an anonymous function and then check to see if it "equals" another different instance. Just because the two anonymous functions you have defined are functionally equivalent does not mean they referentially equivalent i.e. they exist at different memory addresses. The same outcome (false) would be the result in any language.
it's because they are different instances of object so they wont be equal.
=== are used for same objects like checking a boolean variable if it is true or false.
Using === will check 2 things
Object
Equality
This way u can differentiate between 1/0 and true/false.
Which cant be done with ==
function(){} is actually an error for one. Try it, open your console and just type:
function(){}
and press return. It should give you an error. This is because you need to set it as one of the following like:
function foo(){}
var foo = function(){}
(function(){})
It fails because they aren't the same at all.

Categories