Javascript anonymous function argument passing (wrox professionnal javascript p188) - javascript

Wrox Profesionnal Javascript p188
I don't understand this part at line 8 where the anonymous function already have an argument of num, but how can (i) is copied into the argument num. Normally a function would stop at the closing bracket }, adding (i) doesn't make sense for me.
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(num){
return function(){
return num;
};
}(i);
}
return result;
}

This is short hand for calling the function and passing it the parameter i. It's like doing this:
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = myFunction(i);
}
return result;
}
function myFunction(num){
return function(){
return num;
}
}
Thinking of myFunction as the anonymous function my help you understand what's going on, so instead of myFunction(i) you have function(num){...}(i);

It's a closure and a self executing function. i is being "saved" in the scope of the returned function.
var test = "ONE";
var scoped = function () {
alert(test);
}
var saved_scoped = (function (value) {
return function () {
alert(value);
}
})(test);
test = "NOT ONE!";
scoped(); // alerts NOT ONE!
saved_scoped(); // alerts ONE
So you execute the function with the (i) immediately. Then return a function with the i value saved.

Related

Functional Programming: What's the difference between using a closure and using the bind method?

I'm working on a tutorial that explains functional programming. He asked me to come with a solution and it worked, but his solution uses the .bind method of the function.
Is there a difference between our solutions other than the syntax?
function mapForEach(arr, fn) {
var newArr = [];
for(var i = 0; i < arr.length; i++){
newArr.push(fn(arr[i]));
}
return newArr;
}
var arr1 = [1,2,3,4,5];
var checkPassedLimitWithBind = function(limiter){
return function (limiter, item) {
return item >= limiter;
}.bind(this, limiter);
};
var checkPassedLimitWithClosure = function(limiter){
return function (item) {
return item >= limiter;
};
};
var notPassed3 = mapForEach(arr1, checkPassedLimitWithBind(3));
var doesNotPass3 = mapForEach(arr1, checkPassedLimitWithClosure(3));
alert(notPassed3);
alert(doesNotPass3);
The examples can be found here as well:
https://jsfiddle.net/podbarron/73m86cj3/
There is absolutely no behavior difference because that function does not use this.
Otherwise it would be different, yes:
var checkPassedLimitWithBind = function(limiter) {
return function (limiter, item) {
return this == item;
}.bind(this, limiter);
};
var checkPassedLimitWithClosure = function(limiter) {
return function (item) {
return this == item;
};
};
console.log( checkPassedLimitWithBind.call(123)(123) ); // true
console.log( checkPassedLimitWithClosure.call(123)(123) ); // false
The bind solution is unnecessarily complicated. There's no need to partially apply the limiter value there since the function can pretty much access it directly.
Both will end up working the same way. However, it can be different if the variable ever gets reassigned (you'd never want to do it with function arguments).
var checkPassedLimitWithBind = function(limiter){
var fn = function (limiter, item) {
return item >= limiter;
//limiter === argument value for limiter parameter
}.bind(this, limiter);
limiter = 5;
return fn;
};
var checkPassedLimitWithClosure = function(limiter){
var fn = function (item) {
return item >= limiter;
//limiter === 5 all the time
};
limiter = 5;
return fn;
};
Answering the post title: Basically, the closure will have access to whatever value that reference is holding. When you bind the function you'll get that specific value passed down.

Storing closure functions within array using loop

This is the code :
i'm storing the function body inside each element of "resultArr"
, the problem is when i call the stored function _class[0]()i can't reach the exact i it's always 4 !
var checkAttendanceFunc = function(nameArr) {
var resultArr = [];
for(var i = 0; i < nameArr.length; i++) {
resultArr.push(function(){console.log('Is', nameArr[i], 'present?', i);});
}
return resultArrultArr;
};
var _class = checkAttendanceFunc(["alex", "brownex", "chris", "mack"]);
i think it's obvious if i call any item of _class i.e _class[0]() the index will be 4 and the name will be "undefined"
So how wan i solve this problem, i saw some ppl use the apply native function, but i think it works only if we store the function name not the body of a given function
In this case, all the closures inside checkAttendanceFunc point to a reference of the i and nameArr variable.
When the loop is done, i's value is 4 for all the functions you generated, what you need is copying i each time you pass it to a closure.
There are several ways for you to achieve this:
Immediately call the function
var checkAttendanceFunc = function(nameArr) {
var resultArr = [];
for(var i = 0; i < nameArr.length; i++) {
resultArr.push(function(index){
return function(){
console.log('Is', nameArr[index], 'present?', index);
}
}(i));
}
return resultArr;
};
Here you're passing an argument fo the closure and you call it immediately. In this case, i is getting copied and the function has its own value named index.
Use another function that iterates on the array
In this case I'm using Array.forEach
var checkAttendanceFunc = function(nameArr) {
var resultArr = [];
nameArr.forEach(function (value, index){
resultArr.push(function() {
console.log('Is', value, 'present?', index);
});
});
return resultArr;
};
In this case the functions created recieve a copy of value and index, which means they will always point to the same values.
Still not sure I understand the intent of this code, but here's a working version that does what I think you're trying to do:
var students = ["alex", "brownex", "chris", "mack"];
var _class = students.map(function(name, i) {
return function() {
console.log('Is', name, 'present?', i);
};
});
See it in action here.
If you're really just looking for how to make it work with a for-loop, you could always capture it like this:
var checkAttendanceFunc = function(nameArr) {
var resultArr = [];
for(var i = 0; i < nameArr.length; i++) {
resultArr.push((function(idx) {
return function() {
console.log('Is', nameArr[idx], 'present?', idx);
};
})(i));
}
return resultArr;
};
var _class = checkAttendanceFunc(["alex", "brownex", "chris", "mack"]);
Similarly, you can also use .bind():
var checkAttendanceFunc = function(nameArr) {
var resultArr = [];
for(var i = 0; i < nameArr.length; i++) {
resultArr.push((function(idx) {
console.log('Is', nameArr[idx], 'present?', idx);
}).bind(null, i));
}
return resultArr;
};
var _class = checkAttendanceFunc(["alex", "brownex", "chris", "mack"]);
Either way, I personally find the .map() solution much more elegant and readable.

Am I understanding JavaScript closures properly?

Variables created inside a function, cannot be accessed outside the function.
For example in:
function haha()
{
var a = 5;
}
a cannot be accessed outside haha().
And that is where a closure comes in handy:
function haha()
{
var a = 5;
return function hahainside(){ }
}
newfunction = hahainside();
Now, if I call newfunction(), it can access the "a" variable inside the haha().
Am I correct?
I am also wondering why:
<script>
function exclusive()
{
d = "Robert, Ryo, Yuri";
function returnfunction() { alert( d ); }
return returnfunction();
}
ryo = exclusive();
alert(7);
</script>
I am also just wondering why alert(7); does not display on my browser.
Here's what you need to know:
var a = 0;
function haha(){
a = 5; // when calling haha `a` is accessible to everything below where var is declared
return function(){
a = 10; // same as notes above
}
}
var newfunc = haha(); // `a` will become 5 where var is declared
newfunc(); // now `a` is 10 where var is declared
console.log(a); // works
Without having var a declared outside of haha:
function haha(){
var a = 5; // only available in `haha`
return function(){
a = 10; // nearly useless - only scoped to `haha`
}
}
var newfunc = haha(); // `a` will become 5 where var is declared
newfunc(); // now `a` is 10 where var is declared - can't access `a` where `newfunc` is called
console.log(a); // undefined
Maybe you want a Constructor:
function haha(arg){
var whatever = 'something'; // never accessible in a new instance from outside
this.a = arg;
this.hahaInside = function(val){
this.a = val;
}
}
var newfunc = new haha(20); // `newfunc.a` is now `20`
newfunc.a = 12; // `newfunc.a` is now `12`
newfunc.hahaInside(10); // newfunc.a is now 10
As an Object:
var haha = {
a: 5,
hahaInside: function(val){
this.a = val;
}
}
No private variables in an Object, and no Constructor arguments. You don't have to call a new instance as an Object, but you may want an new instance. To avoid writing the keyword this:
if(!Object.create){
Object.create = function(o){
function F(){}
F.prototype = o;
return new F;
}
}
var newfunc = Object.create(haha); // new 'newfunc` is a new instance of `haha`
Real use, no closure:
// assuming 3 radio buttons
var ary = ['a', 'b', 'c'], radioButtons = document.getElementsByName('radButs');
var resultVar = '';
for(var i=0,l=radioButtons.length; i<l; i++){
radioButtons[i].onclick = function(){
resultVar = ary[i];
}
}
// resultVar will always be `'c'` because by the time the click Event is called the loop has run all the through and the scope of `i` is global
A closure prevents a variable from being scoped higher. Global in this case:
// assuming 3 radio buttons
var ary = ['a', 'b', 'c'], radioButtons = document.getElementsByName('radButs');
var resultVar = '';
for(var i=0,l=radioButtons.length; i<l; i++){
(function(i){
radioButtons[i].onclick = function(){
resultVar = ary[i];
}
})(i);
}
// now `resultVar` will be `'a'`, `'b'`, or `'c'` respectively, depending on the radio button that you clicked because `i` becomes separately scoped at each step of the loop even by the time the click Event is called due to user action
You can also use use a closure to create a pseudo-static function like this:
var count = (function(){
var c = 0;
return function(){
return c++;
}
})();
Now every time you call count() it will do just that. The reason this works is because the self-executing function is invoked immediately, scoping var c within it, and returning an unexecuted function that increases c where it was last scoped.

Array values transfer between 2 functions

I try to read an array using a function and use it in another function, however the second function does not seem to read it. What I am doing wrong?
function calcDet () {
var A = []; //generates the array
for (var i = 0; i < k; i++) {
A[i] = [];
for (var j = 0; j < k; j++) {
var id = "A" + (i + 1) + (j + 1);
A[i][j] = parseFloat(document.getElementById(id).value);
}
}
alert (A);
return (A);
}
function calcRec() {
var s;
var det;
alert (A)
}
firstly your array is not declared outside the function. its scope is limited to function body. but as your function returns the array back then try using it for initializing your local variable in other array. also this will work.
or
try declaring it outside the functions
Frist way is
function function1()
{
var valriable1=12;
function2(val);
}
function function2(val)
{
var variableoffunction1 = val;
}
Second way is
var globalvarialbe;
function function1()
{
globalvarialbe=12;
function2();
}
function function2()
{
var local = globalvarialbe;
}
It's because JavaScript has a "functional scope". It means that whatever is declared inside the function cannot be seen by the outside, but what's outside can be seen from the inside.
In your case, you must declare the array outside the function.
var A = []
function calcDet(){...}
function calcRec(){
alert(A);
}
or call the function and return A
function calcDet(){
var A = [];
...
return A;
}
function calcRec(){
var A = calcDet(); //get A from calcDet
alert(A);
}
You can't because you are declaring A locally in calcDet
One way is to declare A outside the function, or simply feed it into calcRec:
var A
function calcDet() {
// code
}
function calcRec() {
// code
}
or (better)
function calcRec() {
var s;
var det;
alert (calcDet())
}
See this link about scope.
The A variable, being declared inside of the function, is only scoped to that function. It will die after the function dies. You need to pass it as a parameter:
function calcRec(data) {
var s;
var det;
alert (data)
}
A = calcDet();
calcRec(A);

new Function() with variable parameters

I need to create a function with variable number of parameters using new Function() constructor. Something like this:
args = ['a', 'b'];
body = 'return(a + b);';
myFunc = new Function(args, body);
Is it possible to do it without eval()?
Thank you very much, guys! Actually, a+b was not my primary concern. I'm working on a code which would process and expand templates and I needed to pass unknown (and variable) number of arguments into the function so that they would be introduced as local variables.
For example, if a template contains:
<span> =a </span>
I need to output the value of parameter a. That is, if user declared expanding function as
var expand = tplCompile('template', a, b, c)
and then calls
expand(4, 2, 1)
I need to substitute =a with 4. And yes, I'm well aware than Function is similar to eval() and runs very slow but I don't have any other choice.
You can do this using apply():
args = ['a', 'b', 'return(a + b);'];
myFunc = Function.apply(null, args);
Without the new operator, Function gives exactly the same result. You can use array functions like push(), unshift() or splice() to modify the array before passing it to apply.
You can also just pass a comma-separated string of arguments to Function:
args = 'a, b';
body = 'return(a + b);';
myFunc = new Function(args, body);
On a side note, are you aware of the arguments object? It allows you to get all the arguments passed into a function using array-style bracket notation:
myFunc = function () {
var total = 0;
for (var i=0; i < arguments.length; i++)
total += arguments[i];
return total;
}
myFunc(a, b);
This would be more efficient than using the Function constructor, and is probably a much more appropriate method of achieving what you need.
#AndyE's answer is correct if the constructor doesn't care whether you use the new keyword or not. Some functions are not as forgiving.
If you find yourself in a scenario where you need to use the new keyword and you need to send a variable number of arguments to the function, you can use this
function Foo() {
this.numbers = [].slice.apply(arguments);
};
var args = [1,2,3,4,5]; // however many you want
var f = Object.create(Foo.prototype);
Foo.apply(f, args);
f.numbers; // [1,2,3,4,5]
f instanceof Foo; // true
f.constructor.name; // "Foo"
ES6 and beyond!
// yup, that easy
function Foo (...numbers) {
this.numbers = numbers
}
// use Reflect.construct to call Foo constructor
const f =
Reflect.construct (Foo, [1, 2, 3, 4, 5])
// everything else works
console.log (f.numbers) // [1,2,3,4,5]
console.log (f instanceof Foo) // true
console.log (f.constructor.name) // "Foo"
You can do this:
let args = '...args'
let body = 'let [a, b] = args;return a + b'
myFunc = new Function(args, body);
console.log(myFunc(1, 2)) //3
If you're just wanting a sum(...) function:
function sum(list) {
var total = 0, nums;
if (arguments.length === 1 && list instanceof Array) {
nums = list;
} else {
nums = arguments;
}
for (var i=0; i < nums.length; i++) {
total += nums[i];
}
return total;
}
Then,
sum() === 0;
sum(1) === 1;
sum([1, 2]) === 3;
sum(1, 2, 3) === 6;
sum([-17, 93, 2, -841]) === -763;
If you want more, could you please provide more detail? It's rather difficult to say how you can do something if you don't know what you're trying to do.
A new feature introduced in ES5 is the reduce method of arrays. You can use it to sum numbers, and it is possible to use the feature in older browsers with some compatibility code.
There's a few different ways you could write that.
// assign normally
var ab = ['a','b'].join('');
alert(ab);
// assign with anonymous self-evaluating function
var cd = (function(c) {return c.join("");})(['c','d']);
alert(cd);
// assign with function declaration
function efFunc(c){return c.join("");}
var efArray = ['e','f'];
var ef = efFunc(efArray);
alert(ef);
// assign with function by name
var doFunc = function(a,b) {return window[b](a);}
var ghArray = ['g','h'];
var ghFunc = function(c){return c.join("");}
var gh = doFunc(ghArray,'ghFunc');
alert(gh);
// assign with Class and lookup table
var Function_ = function(a,b) {
this.val = '';
this.body = b.substr(0,b.indexOf('('));
this.args = b.substr(b.indexOf('(')+1,b.lastIndexOf(')')-b.indexOf('(')-1);
switch (this.body) {
case "return":
switch (this.args) {
case "a + b": this.val = a.join(''); break;
}
break;
}
}
var args = ['i', 'j'];
var body = 'return(a + b);';
var ij = new Function_(args, body);
alert(ij.val);
Maybe you want an annoymous function to call an arbitary function.
// user string function
var userFunction = 'function x(...args) { return args.length}';
Wrap it
var annoyFn = Function('return function x(...args) { return args.length}')()
// now call it
annoyFn(args)
new Function(...)
Declaring function in this way causes
the function not to be compiled, and
is potentially slower than the other
ways of declaring functions.
Let is examine it with JSLitmus and run a small test script:
<script src="JSLitmus.js"></script>
<script>
JSLitmus.test("new Function ... ", function() {
return new Function("for(var i=0; i<100; i++) {}");
});
JSLitmus.test("function() ...", function() {
return (function() { for(var i=0; i<100; i++) {} });
});
</script>
What I did above is create a function expression and function constructor performing same operation. The result is as follows:
FireFox Performance Result
IE Performance Result
Based on facts I recommend to use function expression instead of function constructor
var a = function() {
var result = 0;
for(var index=0; index < arguments.length; index++) {
result += arguments[index];
}
return result;
}
alert(a(1,3));
function construct(){
this.subFunction=function(a,b){
...
}
}
var globalVar=new construct();
vs.
var globalVar=new function (){
this.subFunction=function(a,b){
...
}
}
I prefer the second version if there are sub functions.
the b.apply(null, arguments) does not work properly when b inherits a prototype, because 'new' being omitted, the base constructor is not invoked.
In this sample i used lodash:
function _evalExp(exp, scope) {
const k = [null].concat(_.keys(scope));
k.push('return '+exp);
const args = _.map(_.keys(scope), function(a) {return scope[a];});
const func = new (Function.prototype.bind.apply(Function, k));
return func.apply(func, args);
}
_evalExp('a+b+c', {a:10, b:20, c:30});

Categories

Resources