Currently I'm reading JavaScript book. There is a code snippet in it which I can't understand. What's happening in the line repeat(3, function(n) {? Why we can pass parameter n to the second argument of the function repeat, because in its declaration there is nothing about passing parameters? How does repeat understand that it should pass parameter n to the unless function?
function unless(test, then) {
if (!test) then();
}
function repeat(times, body) {
for (var i = 0; i < times; i++) body(i);
}
repeat(3, function(n) {
unless(n % 2, function() {
console.log(n, "is even");
});
});
// → 0 is even
// → 2 is even
Why we can pass parameter n to the second argument of the function repeat, because in its declaration there is nothing about passing parameters
You are not passing n as the second argument to repeat(), you are passing an anonymous function that takes a single parameter and you chose to name its parameter n (so parameter of the function that is passed in)
Functions in JavaScript are, in simple words, just objects that can also be executed. This means you can pass functions around as parameters to other functions, or add properties to them like you would to objects, etc.
Here's an illustration of what is happening in your example:
Function repeat is defined with two arguments:
repeat(times, body)
So, all you are doing is passing a function as the body argument.
Writing it like this is equivalent:
var times = 3;
var body = function(n) {
unless(n % 2, function() {
console.log(n, "is even");
});
};
repeat(time, body);
How does repeat understand that it should pass parameter n to the unless function?
As you can see above, repeat is not passing anything to unless().
It is your anonymous function (stored in body in my example above) that is actually passing n to unless.
You're not passing a parameter n at all.
In reality, you're passing an entire anonymous function as a parameter (functions are first-class citizens in JavaScript and can be passed around just like other variables).
If you look, the function is passed as the body parameter to the method repeat. repeat then calls the function body with the parameter of i...which is the parameter n in the anonymous function.
If you simply want to write a function to repeat x number of times, and check if it's even, you'd probably want to do it like this:
function repeat(times) {
for (var i = 0; i < times; i++) {
output.innerHTML+= is_even(i)+"\n";
}
}
function is_even(n) {
if ( n % 2 ) return n+" is even";
return n+" is odd";
}
var output = document.getElementById('output');
repeat(6); // Output variable wasn't passed to this function, we're using it globally
<pre id='output'></pre>
Related
I am a beginner to JS world, and I have a question.
when I was studying .forEach() javascript function, I noticed that it takes 2 parameters, the first is a function and the second is the value of This obj and the normal usage like this:
function logArrayElements(element, index, array) {
console.log('a[' + index + '] = ' + element);
}
// Notice that index 2 is skipped since there is no item at
// that position in the array.
[2, 5, , 9].forEach(logArrayElements);
but I noticed also that it can be called also like this:
example num 2 :
[2, 5, , 9].forEach(function(){
console.log(arguments);
});
if .forEach() function takes a callback function as a parameter, how the second example is correct because it takes a function definition not a reference to a function which will be called,
I mean why it accepts a function definition in the second example although it takes a defined function name?
I mean also that forEach need a reference to a function only, so when it loops on each element, it will just add () to the function reference so the function will be called
function definition in javascript returns pointer to that function. You can also go through syntax like
let myFunction = function() { ... } // define function and save it into variable
myFunction() // call the defined function
So passing function by name and passing function definition is same thing
In the second example, the parameter is an anonymous function as compared to first where you defined the function first and used it's reference to pass to .forEach(). So, both are essentially same. You can also write second example like
[2, 5, , 9].forEach(function(element, index, array){
//do something with element
});
If you take a look at Polyfill what it does is it first check if the type of passed callback is a function and if it isn't then it throws an error, otherwise it uses call() to invoke that function so it doesn't matter if its anonymous function or function declaration.
It also checks if number of passed arguments is > 1 or if there is one more parameter after callback and you can access that parameter with this in your callback.
function invoke(callback) {
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
if (arguments.length > 1) var Obj = arguments[1];
var value = 1;
callback.call(Obj, value);
}
invoke(function(e) {
console.log(this)
console.log(1 + e)
}, {foo: 'bar'})
var another = function(e) {
console.log(10 + e)
}
invoke(another);
to reach to the correct answer you have to:
read the correct marked answer comments (the last comment), then read the answer Nenad Vracar as both of them covered my missed approaches, thanks for both of them.
I am making a reduce function that uses another function, which takes multiple arguments, as a callback. My question is, if I wish to test the callback function for whether an argument exists, what syntax would I need to use.
var result = _.reduce([1,2,3], function(memo) {
return memo;
});
_.reduce = function(arr, fun, opt){
//if(arguments[1][1] == undefined) return arr[0];
The last line is my best attempt. What I am trying to say is that, if the function in the result line has no second argument, return arr[0].
If I understand your question correctly, you are trying to access the arguments inside a function call. You can use the arguments object for this.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/length
It allows you to iterate through the arguments of a function and do something with them. For example -
function yourCustomReduceFunction() {
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
Hope this helps :)
I am Following http://eloquentjavascript.net/05_higher_order.html. I have following piece of code
function findEven(number, body) {
for(var i = 0; i < number; i++) body(i)
}
function unless(test, then) {
if(!test) then();
}
findEven(10, function (n) {
unless(n%2, function (n) {
console.log(n, 'is even')
});
});
My question is if i pass variable n into function unless it prints the value 'undefined' to the console. I dont understand why the function unless does not hove the access to its outer scope. Could someone please explain the reason?
Look here
function unless(test, then) {
if(!test) then();
}
And here
unless(n%2, function (n) {
console.log(n, 'is even')
});
The unless function doesn't pass anything to that callback which takes n, so n is undefined.
probably just remove the n from the callback so that it is
unless(n%2, function () {
console.log(n, 'is even')
});
findEven(10, function (n) {
// remove n as an input param
unless(n%2, function () {
console.log(n, 'is even')
});
});
You dont need n inside since you have it as a closure.
Since you are invoking then() without any param - n is undefined.
The outer n is overridden with the inner scope n.
n is undefined because the function then() is called without any argument. The problem lays when you define the function passed in to unless.
The argument n overrides the variable n already defined in the closure. Therefore, because then() is called without arguments, n assumes the value undefined and the console prints undefined.
To fix the bug, just remove n from the arguments:
unless(n%2, function () {
console.log(n, 'is even')
});
JSFiddle : https://jsfiddle.net/5tvafuqt/
I am trying to undrstand the code
for(var i = 0; i < 10; i++) {
setTimeout((function(e) {
return function() {
console.log(e);
}
})(i), 1000)
}
from here http://bonsaiden.github.com/JavaScript-Garden/#function.closures
I understood this method :
for(var i = 0; i < 10; i++) {
(function(e) {
setTimeout(function() {
console.log(e);
}, 1000);
})(i);
}
Can anyone please help me by explaining the first one?
I will try to explain how I understands the first one,
first i is 0,
setTimeout is called,
self calling function "function(e)" is called with i=0,
Im stuck!! what happens when this function returns a function?
All the first one does is return a function that will be called after the timeout happens.
The purpose of it is to create a sub-scope for each iteration of the for loop so that the incrementing i isn't overridden with each iteration.
More explanation:
Lets take this apart into two different pieces:
for(var i = 0; i < 10; i++) {
setTimeout((function(e) {
return function() {
console.log(e);
}
})(i), 1000)
}
This is the first piece:
for(var i = 0; i < 10; i++) {
setTimeout(function(){
console.log(i); //9-9
},1000);
}
Now, when you run this loop, you will always get console.log()'s that contain 9 instead of 0 to 9. This is because each setTimeout is using the same reference to i.
If you wrap the setTimeout part of that in an anonymous function, it creates a scope for each iteration allowing each setTimeout to have it's own i value.
for(var i = 0; i < 10; i++) {
setTimeout((function(i) {
return function() {
console.log(i); // 0-9
}
})(i), 1000)
}
The outer function inside the setTimeout gets executed immediately with an i of 0 for first iteration, 1 for second, etc. That function then in turn returns a function which is the function that setTimeout uses. A function is being generated and returned for each iteration of the loop using a different value for i.
Both end up with the same result: a setTimeout is called with a function to invoke, which writes a number from 0 to 9 on the console. Both use nested functions to get the current value of i into a closure so you don't end up logging 10 9's.
The first code chooses to have a function returning the function that setTimeout will call. The second changes the nesting order so that the closed-over function invokes setTimeout itself. The net effect is the same.
Other than stylistic reasons and personal choice, I don't see a reason to choose one over the other.
"Can you please check the updated question specifying where im getting confused"
OK, here's the long explanation. Remember that the first parameter to setTimeout() needs to be a reference to the function that you want executed after the specified delay. The simplest case is to just name a function defined elsewhere:
function someFunc() {
console.log("In someFunc");
}
setTimeout(someFunc, 100);
Note there are no parentheses on someFunc when passing it as a parameter to setTimeout because a reference to the function itself is required. Contrast with:
setTimeout(someFunc(), 100); // won't work for someFunc() as defined above
With parenthese it calls someFunc() and passes its return value to setTimeout. But my definition of someFunc() above doesn't explictly return a value, so it implicitly returns undefined - which is like saying setTimeout(undefined, 100).
But it would work if changed someFunc() to return a function instead of returning undefined:
function someFunc() {
return function() {
console.log("In the function returned from someFunc");
};
}
So now (at last) we come to the code from your question:
setTimeout((function(e) {
return function() {
console.log(e);
}
})(i), 1000)
Instead of referencing a function by name and calling it as someFunc(i) it defines an anonymous function and calls it immediately as (function(e) {})(i). That anonymous function returns another function and it is that returned function that becomes the actual parameter to setTimeout(). When the time is up it is that returned function that will be executed. Because the (inner) function being returned is defined in the scope of the (outer) anonymous function it has access to the e parameter.
Ok my questions comes from an example from a book that i'm trying to understand.Keep in mind i just got into javascript.
So we have the object set and we define the function foreach. It takes another function as a parameter and invokes it for every item of an array "values" that belongs to set.
set.foreach = function(f,c) {
for(var i = 0; i < this.values.length; i++)
f.call(c,this.values[i]);
};
So far so good..
But i can't understand the usage of the foreach function in the second snipet.In particular i don't understand the role of the variable v. It is not defined enywhere else in the book and i m having a really hard time to understand how this work.We define another function in set to take the values as an array
set.toArray = function() {
var a = [];
this.foreach(function(v) { a.push(v); }); //where did v came from???
return a;
}
set.foreach = function(f,c) {
for(var i = 0; i < this.values.length; i++)
f.call(c,this.values[i]);
}; // ^-------------- being passed right here
The function you passed in is f, and f is invoked having the this value of its calling context set to c, and this.values[i] passed as the first argument.
// ------v---------your function "f" in the forEach
this.foreach(function(v) { a.push(v); });
// ------------^------references the first argument (after the "this" arg)
// that was passed to "f"
Here's a simpler example:
This function accepts a function as a parameter. The only thing it does is call the function:
function my_func( fn ) {
fn();
}
// call my_func, which will call the function you give it
my_func( function() { alert( "hi" ); } );
Live Example: http://jsfiddle.net/6a54b/1/
...so passing the function to my_func will alert the string "hi". No surprise.
But what if my_func provided the value to be alerted?
function my_func( fn ) {
fn( "message from my_func" ); // call the fn passed, giving it an argument
} // ^------------------------------------------------|
// |
// v------references the arg passed by my_func---|
my_func( function( arg ) { alert( arg ); } );
Live Example: http://jsfiddle.net/6a54b/
Now you can see that an argument is being passed to the function we're sending over, and we reference that argument with the arg parameter.
It alerts whatever my_func gave it.
We can even take it one step further, by passing a second argument to my_func that my_func will simply take and pass it to the function we pass in.
function my_func( fn, str ) {
fn( str ); // call the fn passed, giving it
} // the string we passed in
// v------the arg we passed here-----v
my_func( function( arg ) { alert( arg ); }, "I'm getting dizzy!" );
Live Example: http://jsfiddle.net/6a54b/2/
And you can see that both arguments are given to my_func, and my_func calls the function we passed in, passing it the string argument we gave it.
The variable vis an argument being passed to the function. It allows you to work with whatever the function receives. It is no different than namein the following example:
function sayHello(name) {
console.log('Hello '+name);
}
f.call mean calling function f with arguments this.values[i]. this in foreach is set.
about calling foreach from toArray, passing function with v, the values[i] in foreach become v in toArray.
v in this case is being passed in from the call statement f.call(c, this.values[i]). Specifically, it is this.values[i]
The above statement is equivalent to simply:
f(this.values[i])
where f is the function in your 2nd snippet (function(v){ a.push(v); });)
The reason it's typed as .call instead of just calling it is so that the this property can be set, so this in your 2nd function is the array itself, meaning you could type:
function(v){
alert(this.length); // "this" == array
}
v represents each item in the list as your foreach() function loops through them.
so if you have 10 items in your "set" the function will be called 10 times, providing each item in the set to the function as argument v
for example:
set = [1,2,3,4,5];
set.foreach = function(fn, context) {
for(var i = 0; i < this.values.length; i++) {
fn.call(context, this.values[i]);
}
};
set_times_2 = [];
set.foreach(function(item) {
set_times_2.push(item);
set_times_2.push(item);
});
// this is true now:
set_times_2 == [1,1,2,2,3,3,4,4,5,5];
Lots of answers, here's one that specific to your question.
> this.foreach(function(v) { a.push(v); }); //where did v came from???
In the function expression passed to foreach, v is a formal parameter. Including an identifier as a formal parameter is more or less equivalent to declaring it in the function body with var. Maybe it's clearer if written as:
this.foreach( function (v) {
a.push(v);
});
or not...