Using "IIFE" to create private scope; do I need parentheses? - iife

This is my code:
var badget = function () {
var privetVar = 23;
var privetFunc = function (a) {
return privetVar + a;
}
return {
publicFunc: function (b) {
console.log(privetFunc (b));
}
}
}();
It works well; I have access to the publicFunc() using badget.publicFunc(), which has access to the privetVar and privetFunc() due to "closures".
However, someone told me I must use parentheses like this:
var badget = (function() {
var privetVar = 23;
var privetFunc = function(a) {
return privetVar + a;
}
return {
publicFunc: function(b) {
console.log(privetFunc(b));
}
}
})();
Is this second example considered a preferable syntax?

No, the parentheses are not required in this example. Typically people don't use the return value of an IIFE, so the parentheses are required to differentiate a function expression from a function statement.
Since your function declaration in your first example is already part of an assignment expression, it's already a function expression, so the parentheses aren't required.
TL;DR
Valid
var badget = function () {
...
}();
(function () {
...
})();
(function () {
...
}());
Valid (but not necessary)
var badget = (function () {
...
})();
var badget = (function () {
...
}());
Invalid (function statements cannot be IIFEs)
function () {
...
}();

Related

Whats the difference about defining a variable as Function or Function() in dart

What's the diference about setting the type of a variable as Function or Function()?
Function function1 = () { print("1"); };
Function() function2 = () { print("2"); };
// Both works
function1();
function2();
The type Function does just say that your variable points to a Function but does not require this variable to point to a function with a specific signature.
Function() actually gives an analyzer warning on my machine because this is not entirely correct. Instead it should have been void Function() function2 = () { print("2"); };. This specifies that function2 must point to a function which does not return anything and takes zero arguments.
The last is also what would be declared by Dart itself if you have used var or final instead of specifying the type.
The difference becomes clear if you change the method to take an argument:
Function function1 = (int a) { print("1"); }; // works
void Function() function2 = (int a) { print("2"); }; // error

Dart: a closure study

This snippet is of no practical significance. I've been just getting used to the closure idea.
var cls = () {
var x = 5;
return {
'x': x,
'inc': () {x++;},
};
} ();
void main() {
print(cls['x']);
print(cls['inc']);
cls['inc']();
print(cls['x']);
}
DartPad output:
5
Closure '_closure'
5
Error compiling to JavaScript:
main.dart:18:13:
Error: The method 'call' isn't defined for the class 'dart.core::Object'.
The desired output would have been something like
5
6
What'd be the cleanest approach to this kind of exercise?
UPD:
The working example, courtesy of Günter Zöchbauer:
var cls = () {
var x = 5;
var map = <String, dynamic>{
'x': x,
};
map['inc'] = () {map['x']++;};
return map;
} ();
void main() {
print(cls['x']);
print(cls['inc']);
cls['inc']();
print(cls['x']);
}
DartPad output:
5
Closure '_closure'
6
You have to declare the 'x' entry as a Function.
In your code, you set 'x' to the value of the 'x' variable (5) when you return the map. The value will always be 5 and will not update.
var cls = () {
var x = 5;
return {
'x': () => x,
'inc': () {x++;},
};
}();
void main() {
print(cls['x']()); // 5
print(cls['x']); // Closure: () => int
print(cls['inc']); // Closure: () => Null
cls['inc']();
print(cls['x']()); // 6
}
var x = 5;
var cls = () {
return {
'x': x,
'inc': () {x++;},
};
} ();
You would need to move out the variable declaration, otherwise you'd re-declare and re-initialize it to 5 at every call.
update
var cls = () {
var x = 5;
var map = {
'x': x,
// 'inc': () {map['val']++;}, // not possible to reference the `map` variable that is just declared here so we need to move this out
};
map['inc'] = () {map['x']++;};
} ();

JavaScript Module Pattern across multiple files

I'm having to restructure some ancient code, and there's quite a bit of it in lots of different files. The approach is to use the revealing module pattern, as described in JavaScript Module Pattern: In-Depth (section Cross-File Private State).
The first function expression works great, and I can see in Firebug that the function components are also assigned correctly in the second block. But then the variable suddenly ends up undefined.
I put together a simplified example, and the console shows the variable is undefined after the second assignment.
var test = (function ($, ns, undefined)
{
function test1()
{
console.log("executing test1");
ns.testx.test2();
}
return { test1: test1 };
}(jQuery, test || {}));
console.log(test);
var test = (function ($, ns, undefined)
{
ns.testx = (function ()
{
function test2()
{
console.log("executing test2");
}
return { test2: test2 }
})();
}(jQuery, test || {}));
console.log(test);
// DOM ready
$(function ()
{
test.test1();
});
Several variations, such as defining the variable just once at the top don't work either. If the two function expressions are swapped, test 1 is executed but ns.testx is undefined.
I fear I'm missing the blindingly obvious and would really like to understand why this does not work. I also need to get it to work, so any help is greatly appreciated (merging the files into one is not an option).
Try
var test = (function ($, ns, undefined)
{
function test1()
{
console.log("executing test1");
ns.testx.test2();
}
ns.test1 = test1;
return ns;
}(jQuery, test || {}));
console.log(test);
var test = (function ($, ns, undefined)
{
ns.testx = (function ()
{
function test2()
{
console.log("executing test2");
}
return { test2: test2 }
})();
return ns;
/*
This will be
{
test1: test1,
testx: {
test2: test2
}
}
*/
}(jQuery, test || {}));

Javascript Module pattern and closures

I'm trying to get my head around the module pattern in Javascript and have come across various different ways that I can see to do it. What is the difference (if any) between the following:
Person = function() {
return {
//...
}
};
person1 = Person();
function Person2() {
return {
//...
}
}
person2 = Person2();
person3 = function() {
return {
//...
}
}();
person4 = (function() {
return {
// ...
}
})();
person5 = (function() {
return {
// ...
}
}());
They all seem to do the same thing to me.
// This creates a function, which then returns an object.
// Person1 isn't available until the assignment block runs.
Person = function() {
return {
//...
}
};
person1 = Person();
// Same thing, different way of phrasing it.
// There are sometimes advantages of the
// two methods, but in this context they are the same.
// Person2 is available at compile time.
function Person2() {
return {
//...
}
}
person2 = Person2();
// This is identical to 'person4'
// In *this* context, the parens aren't needed
// but serve as a tool for whoever reads the code.
// (In other contexts you do need them.)
person3 = function() {
return {
//...
}
}();
// This is a short cut to create a function and then execute it,
// removing the need for a temporary variable.
// This is called the IIFE (Immediate Invoked Function Expression)
person4 = (function() {
return {
// ...
}
})();
// Exactly the same as Person3 and Person4 -- Explained below.
person5 = (function() {
return {
// ...
}
}());
In the contexts above,
= function() {}();
= (function() {}());
= (function() {})();
All do exactly the same thing.
I'll break them down.
function() {}();
<functionExpression>(); // Call a function expression.
(<functionExpression>()); // Wrapping it up in extra parens means nothing.
// Nothing more than saying (((1))) + (((2)))
(<functionExpression>)();
// We already know the extra parens means nothing, so remove them and you get
<functionExpression>(); // Which is the same as case1
Now, all of that said == why do you sometimes need parens?
Because this is a *function statement)
function test() {};
In order to make a function expression, you need some kind of operator before it.
(function test() {})
!function test() {}
+function test() {}
all work.
By standardizing on the parens, we are able to:
Return a value out of the IIFE
Use a consistent way to let the reader of the code know it is an IIFE, not a regular function.
The first two aren't a module pattern, but a factory function - there is a Person "constructor" that can be invoked multiple times. For the semantic difference see var functionName = function() {} vs function functionName() {}.
The other three are IIFEs, which all do exactly the same thing. For the syntax differences, see Explain the encapsulated anonymous function syntax and Location of parenthesis for auto-executing anonymous JavaScript functions?.
I've found a extremely detail page explaining this kind of stuff
Sth called IIFE
Hope will help.

Optional callback with optional parameter

I may be doing something wrong syntactically or practically so "don't do that" could be valid but it seems this should work:
class Thing {
//static dynamic noop = () { }; // fails
static dynamic noop = ([dynamic value]) { }; // works for null cases
dynamic _callback;
Thing._([dynamic callback([dynamic value])])
: this._callback = callback != null ? callback : Thing.noop;
factory Thing([dynamic callback([dynamic value])]) {
return new Thing._(callback);
}
}
When I run these tests, the first one fails but the second, third and fourth pass:
//Caught type '() => dynamic' is not a subtype of type '([dynamic]) => dynamic' of 'callback'.
test('callback with optional param', () {
var thing = new Thing(() { });
thing.doCallback();
thing.doCallback('data');
});
test('callback with optional param', () {
var thing = new Thing(([_]) { });
thing.doCallback();
thing.doCallback('data');
});
test('callback with optional param', () {
var thing = new Thing();
thing.doCallback();
thing.doCallback('data');
});
test('callback with optional param', () {
var thing = new Thing(null);
thing.doCallback();
thing.doCallback('data');
});
dynamic callback([dynamic value]) means a callback that can take one parameter or none. In your first test case, the callback you provides (() { }) only handles calls with no parameter. So it does not respect the contract. That's why you get this error.

Resources