Explain the Encapsulated Anonymous Function Syntax

Explain the encapsulated anonymous function syntax

It doesn't work because it is being parsed as a FunctionDeclaration, and the name identifier of function declarations is mandatory.

When you surround it with parentheses it is evaluated as a FunctionExpression, and function expressions can be named or not.

The grammar of a FunctionDeclaration looks like this:

function Identifier ( FormalParameterListopt ) { FunctionBody }

And FunctionExpressions:

function Identifieropt ( FormalParameterListopt ) { FunctionBody }

As you can see the Identifier (Identifieropt) token in FunctionExpression is optional, therefore we can have a function expression without a name defined:

(function () {
alert(2 + 2);
}());

Or named function expression:

(function foo() {
alert(2 + 2);
}());

The Parentheses (formally called the Grouping Operator) can surround only expressions, and a function expression is evaluated.

The two grammar productions can be ambiguous, and they can look exactly the same, for example:

function foo () {} // FunctionDeclaration

0,function foo () {} // FunctionExpression

The parser knows if it's a FunctionDeclaration or a FunctionExpression, depending on the context where it appears.

In the above example, the second one is an expression because the Comma operator can also handle only expressions.

On the other hand, FunctionDeclarations could actually appear only in what's called "Program" code, meaning code outside in the global scope, and inside the FunctionBody of other functions.

Functions inside blocks should be avoided, because they can lead an unpredictable behavior, e.g.:

if (true) {
function foo() {
alert('true');
}
} else {
function foo() {
alert('false!');
}
}

foo(); // true? false? why?

Should I encapsulate blocks of functionality in anonymous JavaScript functions?

You're right that sticking variables inside an anonymous function is a good practice to avoid cluttering up the global object.

To answer your latter two questions: It's completely impossible for the interpreter to know that an object won't be used again as long as there's a globally visible reference to it. For all the interpreter knows, you could eval some code that depends on window['aVar'] or window['operation'] at any moment.

Essentially, remember two things:

  1. As long as an object is around, none of its slots will be magically freed without your say-so.
  2. Variables declared in the global context are slots of the global object (window in client-side Javascript).

Combined, these mean that objects in global variables last for the lifetime of your script (unless the variable is reassigned). This is why we declare anonymous functions — the variables get a new context object that disappears as soon as the function finishes execution. In addition to the efficiency wins, it also reduces the chance of name collisions.

Your second example (with the inner anonymous function) might be a little overzealous, though. I wouldn't worry about "helping the garbage collector" there — GC probably isn't going to run in the middle that function anyway. Worry about things that will be kept around persistently, not just slightly longer than they otherwise would be. These self-executing anonymous functions are basically modules of code that naturally belong together, so a good guide is to think about whether that describes what you're doing.

There are reasons to use anonymous functions inside anonymous functions, though. For example, in this case:

(function () {
var bfa = new Array(24 * 1024*1024);
var calculation = calculationFor(bfa);
$('.resultShowButton').click( function () {
var text = "Result is " + eval(calculation);
alert(text);
} );
})();

This results in that gigantic array being captured by the click callback so that it never goes away. You could avoid this by quarantining the array inside its own function.

Why the difference in anonymous function definition syntax?

Here's my attempt at an explanation. There are two parts.

First, the anonymous literal syntax. When you write #(+ 10 %), it gets expanded into something that is functionally similar to the following:

(fn [x] (+ 10 x))

For ex.

=> (macroexpand '(#(+ 10 %))

Would return something like:

(fn* [p1__7230#] (+ 10 p1__7230#))

The second part. When you use the threading macro, as the docs say, the macro expands by inserting the first argument as the second item into the first form. And if there are more forms, inserts the first form as the second item in second form, and so on.

The key term here is second item. It doesn't care about what forms you are providing as arguments, it will just do an expansion using that rule.

So, to combine both the points, when you use

(-> 5 #(+ 10 %) #(* 2 %))

following the rules, it gets expanded into something that is functionally similar to this

(fn (fn 5 [x] (+ 10 x)) [y] (* 2 y))

which doesn't compile.

Also, as a side note, the form (+ 10) is not an anonymous function. It is a partial function call that gets updated with arguments during macro expansion. And by 'partial', I mean in the literal sense, not in the functional programming sense.

Update

To explain why it works when you enclose the anonymous literal within parentheses (as a comment on the question says), you can infer the results from these two rules. For ex.

 => (macroexpand '(#(+ 10 %)))

would result in the functional equivalent of

((fn [x] (+ 10 x)))

So, when an item is inserted in its second place, it would look like

((fn [x] (+ 10 x)) 5)

Which is equivalent to

(#(+ 10 %) 5)

Cleanest way to access class member objects into an anonymous function

Elegant solution you are looking for is using arrow function:

useAnonymousFunction() {
setTimeout(() => this.printA())
}

Why does wrapping a callback in an anonymous function change the meaning of 'this'?

Using an anonymous function wraps MyObj in a closure. That closure's lexical scope (execution context) is now localized to the closure. So this is localized to the closure (and MyObj) as well.

You can discover that by using a debugger with a break point set on the callback() call.

This image shows the variable structure with the closure in place:

With anonymous function wrapper

Without the function wrapper, the lexical scope is the same scope as the higherOrder() function - which is the global scope. Again, this is demonstrated with a break point on the same line of code (note lack of closure):

Without wrapper

Note: this code is run in node - so no Window object here.



Related Topics



Leave a reply



Submit