My code is like this:
Example 1:
var fn = (function () {
function fn (a, b, c) {
/* CODE HERE */
};
return fn;
})();
fn(a, b, c);
Example 2:
var fn = function fn (a, b, c) {};
fn(a, b, c);
what is the difference between this two calls? I'm trying to refact some codes. When i try to put out the fn function like the second example, it fails.
The most common use case for IIFE is to create a closure with some private variables inside of it. For example:
var counter = (function() {
// This variable is private. You cannot change it from the outer code.
var i = 0;
return function() {
return i++;
};
})();
console.log(counter());
console.log(counter());
console.log(counter());
outputs:
0
1
2
So, when you refactor IIFE to regular functions you have to make sure that you deal with closures in the right way.
Related
(function foo() { var a=b=c=1 }())
When I try to log a will return a not defined err, however, when I try to log b or c will return the value 1. It's wicked.
b and c are added into the window object and get their values as 1. But a is declared via var. This means that a is visible only in the function context and not outside from it.
Your code is equivalent
(function foo() {
c = 1;
b = c;
var a = b;
}())
however, when I try to log b or c will return the value 1.
Because you didn't localized the scope (inside the function) of b and c by using var or let or const.
Without var, let or const, these variable will take the scope in which this function is defined.
If the outer scope (not outermost) also doesn't localize those variables, then parent scope is checked again till the outermost scope (window). And the variable gets added to outermost scope if no local scope is defined for them. for example
function a() {
(function foo() {
var a = b = c = 1;
}());
console.log(b, c); //print 1,1
}
a();
console.log(b, c); //print 1,1
However, if these variables are defined in outer scope, then they don't get added to the outermost (window) scope. For example, following will throw an error.
function a() {
var b,c;
(function foo() {
var a = b = c = 1;
}());
a();
console.log(b, c);
}
console.log(b, c);
If you have lots of constructs where you want to initialise to some constants and you can use ES6 features the following is a nice way to do it.
//store function in your lib
function* initVar(value) {
while (true) yield value;
}
//using function
let
[a,b,c] = initVar(0),
[d,e,f] = initVar("xyz"); //not just limited to numbers.
console.log(a,b,c,d,e,f);
I need to call a function with the same parameter's values to refresh a ChartJs with a new daterange.
The _reportDateStart and _reportDateEnd are updated outside of the function, so I need to recall the function so the chart is updated with the new data.
The script is:
var _reportDateStart;
var _reportDateEnd;
var _loadChart = function (chartLabel, queryMetrics, queryDimensions) {}
The call is made like this:
_loadChart("Visits", "ga:sessions", "ga:date,ga:nthDay");
But can also be:
_loadChart("Users", "ga:users", "ga:date,ga:nthDay");
Declare globally accessible variables and assign the parameters on every call that way you can call the function with those variables again:
Example:
var param1,param2,param3;
var _loadChart = function(a, b, c){
param1 = a;
param2 = b;
param3 = c;
//rest of the code.
};
function callTheFunctionAgain(){
_loadChart(a, b, c);
}
_loadChart("Visits", "ga:sessions", "ga:date,ga:nthDay");
callTheFunctionAgain();
to do this you can create a new function with bound param as you wish like this var _loadChartBounded = _loadChart.bind(null, "Visits", "ga:sessions", "ga:date,ga:nthDay")
then every time you call _loadChartBounded() it will get the same param
We already have global variables and .bind()
I will throw in another solution which uses a closure
For an explanation on how these work, head over to this question and its excellent answers:
How do JavaScript closures work?
// This is only an example.
// Please change the variable names to something more meaningful :)
var _loadContent = (function() {
var _a, _b, _c;
return function(a, b, c) {
if (typeof _a === "undefined") {
_a = a;
_b = b;
_c = c;
}
console.log(_a, _b, _c);
}
}());
_loadContent(1, 2, 3);
_loadContent(4, 5, 6);
_loadContent();
For those arriving in the now (15 Jun 2020), here's the most robust way to call a function from within it:
let fn = (a, b, c) => {
/* fn's content */
fn(...arguments);
}
This works great if you don't know what the parameters will be (user input), or simply do not want to have to change the parameters in multiple places when refactoring the code.
Reference
I saw this shortcut given as an answer on a code Kata but I am having difficulty understanding exactly what the below example is doing.
function func(fn) {
return fn.bind.apply(fn, arguments);
}
So far my understanding is that bind creates a new function similar to doing the following:
function func(fn) {
return function () {
return fn.apply(fn, arguments);
};
}
Is this the case? Any clearer answers or breakdowns of what is going on would be great.
fn.bind
is just
Function.prototype.bind
So we're applying bind to fn, returning
fn.bind(arguments[0]/* doesn't matter, it's fn*/, arguments[1], arguments[2], etc.)
So the bound function is called with arguments being the arguments of func after fn.
Another way to write it would have been:
function func(fn) {
var args = [].slice.call(arguments, 1);
return function () {
var localArgs = [].slice.call(arguments);
return fn.apply(fn, args.concat(localArgs));
};
}
The fact that the context of the call is the initial function (arguments[0]) is most certainly only a side effect. The important thing is we wrap the arguments with the function, but make it possible to dynamically pass other arguments.
Example 1, wrapping all arguments :
function add(a,b){
return a+b
}
var f = func(add, 2 ,3); // f is a function which will always apply add to 2 and 3
console.log(f()) // logs 5
Exemple 2, currying:
function multiply(a,b){
return a*b
}
var multBy2 = func(multiply, 2);
console.log(multBy2(3)) // logs 6
I came across this syntax in "Hey Underscore, You're Doing it Wrong" JavaScript talk (4:15). I would like to know what it means.
var add = function(x,y){
return x + y;
}.autoCurry();//What is happening in this line.
First let's looks at what curry and autocurry actually do. I've annotated the source of these two functions (originally found in the wu.js library):
////
// Type:
//
// ((a,b, ... c) -> d) -> a -> b -> ... -> c -> d
//
// Example:
//
// function add(a, b) { return a + b; }
// add2 = curry(add, 2)
// add2(3)
// // 5
function curry(fn /* variadic number of args */) {
var args = Array.prototype.slice.call(arguments, 1);
function f() { return fn.apply(this, args.concat(toArray(arguments))); }
return f;
}
////
// Example:
//
// function add(a, b) { return a + b; }
// autoCurry(add);
//
// add(2)(3)
// // 5
//
// add(2, 3)
// // 5
function autoCurry(fn, numArgs) {
numArgs = numArgs || fn.length;
function f() {
if (arguments.length < numArgs)
{
return numArgs - arguments.length > 0 ?
autoCurry(curry.apply(this, [fn].concat(toArray(arguments))),
numArgs - arguments.length) :
curry.apply(this, [fn].concat(toArray(arguments)));
}
else
{
return fn.apply(this, arguments);
}
}
f.toString = function() { return fn.toString(); };
f.curried = true;
return f;
}
In other words,
autoCurry(add)
Takes a function that takes two arguments and returns a number, and returns a function A that takes a single argument and returns a function B. Where B is a function that takes a single argument and returns a number:
add(1) -> returns a function add1(), which itself takes a single argument.
Next, the speaker in that talk does the following:
Function.prototype.autoCurry = function(n) { return autoCurry(this, n); }
This simply applies the autoCurry method to any given function (self) so that
var add = function(x,y){
return x + y;
}.autoCurry();
Has the same effect as:
var add = function(x,y) { return x + y; };
add = autoCurry(add)
Well, I can't tell you what, exactly autoCurry is doing... ...but what I can tell you is this:
They've modified the Function constructor's prototype Function.prototype.autoCurry = function () { };
Every new function you make on that page will now have access to this method as one of its properties.
var myFunc = function () { return true; }; myFunc.autoCurry();
You can chain statements together, happily in JS.
var myObj = { run : function () { } }, result = myObj.run(); is the same as
var result = { run : function () { } }.run();, as long as you don't care about myObj after.
So:
You are creating a function, and as soon as it's created, you're running a method on it, and the return statement of that method (the last thing in the chain) is being saved to the variable.
Now, currying is a form of taking a function and wrapping it in other functions, which allows you to call it with only a portion of the arguments needed.
function add_two_numbers = function (x, y) { return x + y; }
Currying would allow you to do this:
var save_x_for_later = curry(add_two_numbers),
save_y_and_add = save_x_for_later(3),
result = save_y_and_add(5);
result; // 8
As for your new title, the answer is the following:
You will get an error thrown in your face:
.autoCurry() is not a part of the language.
It was written, by hand, and put on the Function.prototype as Function.prototype.autoCurry = function () { }
I could go into an implementation of currying, but there's a lot of stuff to wrap your head around, if you haven't done much functional programming, or if "lambda" is a head-scratching term.
In JavaScript, a function instantiation expression:
function name( arg1, arg2, ... ) { /* code */ }
creates a function and results in a reference to the function object. Thus, the .autoCurry() is a reference to a property on that object, which is apparently assumed to be a function.
I suspect that the example you're looking at has some other code that adds "autoCurry" to the Function prototype object. That way, every function object has access to that function as the "autoCurry" property.
I wrote a program like this:
function a(x,y,z) {
function b(foo,bar) {};
function c(foo,bar) {};
function d(foo,bar) {};
function e(foo,bar) {};
function f(foo,bar) {};
}
I call the function this way:
for(var i=0; i<5; i++) { charts[i] = a(x[i],y[i],z[i])}
x,y and z are global arrays of length 5 and some properties.
Now, the loop gets executed before page load and all the functions for each of the array is also executed as expected (There are event listeners bound to elements in these functions)
Let's say I want to access some local variables from b,c,d,e or f "after" page load, when an event is invoked, how do i do it? I'm talking about "scope" here I think.
Do I have to make the whole thing an object?
Also, there are local variables inside b,c,e and f (locally declared and not using "this").
There are also variables inside of a which is accessed by b,c,d,e and f (Again, locally declared, not using "this")
Thanks!
You can simple create a new object inside a and return that object.
var a = function (x, y, z) {
var result = {};
var outerVal = x;
result.b = function (foo, bar) { return foo + bar; };
result.c = function (foo, bar) { return outerVal + result.g + z}; //closure
result.d = function (foo, bar) { };
result.e = function (foo, bar) { };
result.f = function (foo, bar) { };
result.g = y;
//If you want to execute the functions you can do so
result.bValue = result.b(x, y);
result.c(y, z);
return result;
};
var anA = a(1, 2, 3);
console.log(anA.bValue); //3
console.log(anA.b(2, 5)); //7
console.log(anA.c()); //6
What Amberlamps said, you cannot access local variables from outside of the scope they are created, meaning your function a cannot "see" any variables created in b, c, d, e, f. You could either create some global variables (global to b, c, d, e and f) or you could consider writing a closure:
var something = (function () {
var globalOne = null,
globalTwo = null;
//...
return {
a: function (x, y, z) {
something.b(foo, bar);
something.c(foo, bar);
},
b: function (foo, bar) {
},
c: function (foo, bar) {
}
// etc.
};
}());
This could be a little overkill for what you're trying to do, but what's nice with the closure is that your globals globalOne and globalTwo cannot be modified by the client.