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...
Related
I am new to JavaScript and have several questions about functional programming.
Here is a statement:
outer(inner(5));
Is it possible to construct function outer in a way that allows it
to capture function inner and its argument 5?
Is it possible to construct function inner in a way that allows it to
pass itself and its argument 5 to function outer?
If the answer to both questions above is no, is it possible to
construct functions outer and inner in a way that allows the former
to capture function inner and its argument 5 or the
latter to pass itself and its argument 5 to function
outer?
I tried:
using the arguments object but to no avail.
function outer (parameter) {
return arguments;
}
function inner (n) {
return n + 1;
}
console.log(outer(inner(5))); // returns Arguments { 0: 6 ... }
using currying but I do not see how it can help me since I am not given the following statement:
outer()(5);
A possible workaround consists in returning an array from inner() composed of on one side the processing function and on the other side the argument.
outer will be able to access both by reading the array.
function outer(arr)
{
var fun = arr[ 0 ];
var arg = arr[ 1 ];
var result = fun(arg);
console.log('inner function is:', fun);
console.log('its argument is:', arg);
console.log('its result is:', result);
return result;
}
function inner(num)
{
return [
function (_num)
{
return _num + 1;
},
num
]
}
console.log(outer(inner(5)));
You could achieve this by letting your inner return a function (foo) which closes over n. You can then let foo return n+1. Then, within your outer function, you can invoke foo to get its return value:
const outer = f => f();
const inner = n => _ => n+1;
console.log(outer(inner(5)));
Alternatively, another possibility would involve changing your return value. You could return an array from inner which contains the original passed through arguments (...arguments) and the returned value (to_return) and then use destructuring assignment to get the passed in argument(s) (n & m) and the returned result:
function outer([result, n, m]) {
console.log("returned from inner: ", result);
console.log("arguments passed into inner: " + [n, m]);
return n;
}
function inner(n, m) {
let to_return = n + 1;
return [to_return, ...arguments];
}
console.log(outer(inner(5, 2))); // returns 5
Note: I added an m argument to demonstrate how you can extend this to multiple arguments
function outer(myFunction, argument) {
if (typeof myFunction !== "function") {
return false;
}
return myFunction(argument);
}
function inner(n) {
return n + 1;
}
console.log(outer(inner, 5));
Just a simple approach. Don’t execute the function inner but pass it as an argument (myFunction). And let the outer function execute it with the given argument.
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 using a function as a parameter to build a reduce method. If the function that is passed in has no arguments, then I want to return 0.
_.reduce = function(arr, fun){
if(fun[0] == undefined){
return 0;
}
.
.
The issue is that the if statement executes even if an argument is passed into fun. Am I trying to access the arguments incorrectly?
If you want to know how many arguments a function takes you should check it's length.
_.reduce = function(arr, fun) {
if (!fun || !fun.length) {
return 0;
}
...
};
Considering your function "fun" is always defined, you can use the .length according to this link :
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length
_.reduce = function(arr, fun){
if(fun.length == 0){
return 0;
}
I just started playing around with functional programming and am trying to pass a function as an argument of another function. However the function that I am trying to pass also has arguments like so:
function splitStringBy(string, type, func) {
// Split string by type.
var splitArray = string.split(type);
console.log(splitArray);
// Do something with the array.
func !== undefined ? func(splitArray) : null;
}
function loopArray(array, func) {
// Loop through array.
for (var i = 0; i < array.length; i++) {
func(array[i]);
}
}
I need to pass splitArray to my loopArray()
Here's how I'm trying to call it:
splitStringBy($scope.textSpace, "<br>", loopArray(splitArray, function() {
console.log('It worked!');
}));
Console comes up with Error: splitArray is not defined.
Rather than passing loopArray as a function, you're actually calling it, then passing its return value to splitStringBy. Since splitArray isn't defined when you first reference it, it's throwing that error.
What you want to do is something like this:
function splitStringBy(string, type, func) {
// Split string by type.
var splitArray = string.split(type);
console.log(splitArray);
// Do something with the array.
func !== undefined ? func(splitArray) : null;
}
function loopArray(func) {
// Return function for looping.
return function(array) {
// Loop through array.
for (var i = 0; i < array.length; i++) {
func(array[i]);
}
}
}
splitStringBy($scope.textSpace, "<br>", loopArray(function() {
console.log('It worked!');
}));
This is called currying, where a function passes a function as a return value. loopArray will create a function, then return it. We then pass the newly made function to splitStringBy, which then invokes it.
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>