I'm trying to understand this functional style code from the book Eloquent Javascript:
http://eloquentjavascript.net/chapter6.html#exercise1
When the count() function passes an anonymous function to reduce() the code works. But if I break the function out into a helper function then I get a reference error.
Can anyone explain why count() works but countHelper() does not?
var numbers = [1,2,3,0,1,2,3,0]
function forEach(array, action) {
for (var i = 0; i < array.length; i++)
action(array[i]);
}
function reduce(combine, base, array) {
forEach(array, function (element) {
base = combine(base, element);
});
return base;
}
function equals(x) {
return function(element) { return x === element;};
}
function count(test, array) {
return reduce(function(base, element) {
return base + (test(element)?1:0);
}, 0, array);
}
function countHelper(test, array) {
function helper(base, element) {
return base + (test(element)?1:0);
}
return reduce(helper(base, element), 0, array);
}
function countZeroes(array) {
return count(equals(0), array);
}
print(countZeroes(numbers)) // 2
function countZeroesHelper(array) {
return countHelper(equals(0), array);
}
print(countZeroesHelper(numbers)) // ReferenceError: base is not defined
In countHelper(), you are actually calling the helper function immediately when you pass arguments to reduce() and passing its return value to reduce (which isn't what you want), rather than passing a reference to the function so reduce() can call the function when it wants to. You have this:
function countHelper(test, array) {
function helper(base, element) {
return base + (test(element)?1:0);
}
return reduce(helper(base, element), 0, array);
}
It should be this:
function countHelper(test, array) {
function helper(base, element) {
return base + (test(element)?1:0);
}
return reduce(helper, 0, array);
}
Note the difference in arguments to the reduce() function.
When you want to pass a function as an argument, you don't include the parens after it because that just causes it to be executed right away and passes the return value from executing it rather than just passing a reference to the function itself.
This is a common mistake in an untyped language like Javascript that lets you pass anything in any argument. Even seasoned programmers occasionally make this mistake (myself included). The important distinction to understand is the difference between executing the function vs. passing a reference to the function.
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 have a few functions in two different files that are all linked together by function calls they are as follows
FILE 1:
function getFunction(func){
}
FILE 2:
function Numbers(one, two) {
return (one*two);
}
var func = getFunction(Numbers);
and these are called by:
func(input_array);
my array has values 1,3,5,7,9 and I need func(input_array) to return 3,15,35,63,9 (the last value loops back to the first value)
basically what I am trying to do is have getFunction return a function such that these values are calculated. I am having trouble because I can't wrap my mind about sending and returning functions. I don't know how to access the array if it isn't sent into the function. Let me know if I need to clarify anything.
function getFunction(callback) {
return function(array) {
return array.map(function(cur, index) {
return callback(cur, array[(index+1) % array.length]);
});
};
}
getFunction returns a closure over the callback parameter, which is the function that you want to call. The closure receives the array parameter, and it calls the callback in a loop over the array using array.map. The % modulus operator performs the wraparound that you want.
Another way to write this that may be clearer is:
function getFunction(callback) {
return function(array) {
var result = [];
for (var i = 0; i < array.length; i++) {
j = (i+1) % array.length; // Next index, wrapping around
result.push(callback(array[i], array[j]));
}
return result;
};
}
var func = getFunction(Numbers);
console.log(func([1,3,5,7,9])); // Logs [3,15,35,63,9]
here is simple function that returns what you need
function Numbers(x) {
output_array=[];
for(i=0;i<x.length;i++){
if(x[i+1]==undefined){
output_array.push(x[i]);
}
else{
output_array.push(x[i]*x[i+1]);
}
}
return output_array;
}
var input_array=[1,3,5,7];
var num = Numbers(input_array);
console.log(num);
OR if you need it in the way function calling another function
and than returning the result use this
function getFunction(Numbers,input_array){
return Numbers(input_array);
}
function Numbers(x) {
output_array=[];
for(i=0;i<x.length;i++){
if(x[i+1]==undefined){
output_array.push(x[i]);
}
else{
output_array.push(x[i]*x[i+1]);
}
}
return output_array;
}
var input_array=[1,3,5,7];
var num = getFunction(Numbers,input_array);
console.log(num);
I have a very basic question about JavaScript.
Consider the following code:
var numbers = [4,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(function(item,index,array) {
alert(arguments.length);
return (item > 1);
});
Now in the above code I am passing anonymous function as an argument of "every" function.
How exactly my anonymous function is getting the exactly 3 arguments(item,index,array).
This isn't really a basic javascript question, but a library question, and how it "happens" depends on the implementation.
This here is a sample implementation of every in javascript:
function every(array, fn) {
for(var i = 0; i < array.length; i++) {
fn(array[i], i, array);
}
}
You would call it like this:
every([1,2,3,4], function(item, index, array) {
// do stuff
});
As you can see, it's the every function itself, that calls the fn (which is the function you pass in), and decides what arguments to pass.
The anonymous function you're passing is simply provided as argument for every() method which calls it for a number of times. every() iterates through your list items and calls your anonymous function each time with three arguments: value, index and your entire array.
Here's an approximate source code of how the actual every() function works:
Array.prototype.every = function(callback) {
for(i=0; i<this.length; i++) {
callback(this[i], i, this);
}
}
Let's build a simple function with a callback argument:
function foo(callback)
{
var callbackArgument = 'bar';
callback(callbackArgument);
}
Let's use it:
foo(function(arg){
console.log(arg);
}); // logs "bar" to the console!
How exactly my anonymous function is getting the exactly 3
arguments(item,index,array)?
Maybe it would be easier to understand with an alternative example You have:
var numbers = [4,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(function(item,index,array) {
alert(arguments.length);
return (item > 1);
});
You could also write the same in the following manner:
var numbers = [4,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(item,index,array) {
function anonymous(firstVar,secondVar,thirdVar){
//do your anonymous stuff here
alert(thirdVar.length);
return (firstVar > 1);
}
//get the anonymous function processed data
var anonymousFunctionResults = anonymous(item,index,array);
//do your original stuff that you would have done with the results of anonymous function
anonymousFunctionResults...
}
});
Or in this way:
function anonymous(firstVar,secondVar,thirdVar){
//do your anonymous stuff here
alert(thirdVar.length);
return (firstVar > 1);
}
var numbers = [4,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(item,index,array, anonymous) {
//get the anonymous function processed data
var anonymousFunctionResults = anonymous(item,index,array);
//do your original stuff that you would have done with the results of anonymous function
anonymousFunctionResults...
}
});
Or in this way:
function anonymous(firstVar,secondVar,thirdVar){
//do your anonymous stuff here
alert(thirdVar.length);
return (firstVar > 1);
}
var numbers = [4,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(anonymous(item,index,array)) {
//get the anonymous function processed data
//you can use the "firstParameter" variable already of course
//this is just to make a point
var anonymousFunctionResults = firstParameter;
//do your original stuff that you would have done with the results of anonymous function
anonymousFunctionResults...
}
});
If I understood your question well :)
Object.prototype.e = function() {
[].forEach.call(this, function(e) {
return e;
});
};
var w = [1,2];
w.e(); // undefined
But this works if I use alert instead
// ...
[].forEach.call(this, function(e) {
alert(e);
});
// ...
w.e(); // 1, 2
I realize this is an old question, but as it's the first thing that comes up on google when you search about this topic, I'll mention that what you're probably looking for is javascript's for.. in loop, which behaves closer to the for-each in many other languages like C#, C++, etc...
for(var x in enumerable) { /*code here*/ }
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/for...in
http://jsfiddle.net/danShumway/e4AUK/1/
A couple of things to remember :
for..in will not guarantee that your data will be returned in any particular order.
Your variable will still refer to the index, not the actual value stored at that index.
Also see below comments about using this with arrays.
edit: for..in will return (at the least) added properties to the prototype of an object. If this is undesired, you can correct for this behavior by wrapping your logic in an additional check:
for(var x in object) {
if(object.hasOwnProperty(x)) {
console.log(x + ": " + object[x]);
}
}
Your example is a bit odd, but as this question is becoming the canonical "return from forEach" question, let's use something simpler to demonstrate the problem:
Here, we have a function that checks the entries in an array to see if someProp matches value and, if so, increments the count on the entry and returns the entry:
function updateAndReturnMatch(array, value) {
array.forEach(function(entry) {
if (entry.someProp == value) {
++entry.count;
return entry;
}
});
}
But calling updateAndReturnMatch gives us undefined, even if the entry was found and updated.
The reason is that the return inside the forEach callback returns from the callback, not from updateAndReturnMatch. Remember, the callback is a function; return in a function returns from that function, not the one containing it.
To return from updateAndReturnMatch, we need to remember the entry and break the loop. Since you can't break a forEach loop, we'll use some instead:
function updateAndReturnMatch(array, value) {
var foundEntry;
array.some(function(entry) {
if (entry.someProp == value) {
foundEntry = entry;
++foundEntry.count;
return true; // <== Breaks out of the `some` loop
}
});
return foundEntry;
}
The return true returns from our some callback, and the return foundEntry returns from updateAndReturnMatch.
Sometimes that's what you want, but often the pattern above can be replaced with Array#find, which is new in ES2015 but can be shimmed for older browsers:
function updateAndReturnMatch(array, value) {
var foundEntry = array.find(function(entry) {
return entry.someProp == value;
});
if (foundEntry) {
++foundEntry.count;
}
return foundEntry;
}
The function e() isn't returning anything; the inner anonymous function is returning its e value but that return value is being ignored by the caller (the caller being function e() (and can the multiple uses of 'e' get any more confusing?))
Because
function(e) {
return e;
}
is a callback. Array.forEach most likely calls it in this fashion:
function forEach(callback) {
for(i;i<length;i++) {
item = arr[i];
callback.call(context, item, i, etc.)
}
}
so the call back is called, but the return doesn't go anywhere. If callback were called like:
return callback.call();
the it would return out of forEach on the first item in the array.
You can use for...of to loop over iterable objects, like array, string, map, set... as per Mozilla docs.
const yourArray = [1, 2, 3]
for (const el of yourArray) { // or yourMap, Set, String etc..
if (el === 2) {
return "something"; // this will break the loop
}
}
I have a requirement where I get the anchor tags id and based on the id I determine which function to execute.. so is there anything that suites below code
function treeItemClickHandler(id)
{
a=findDisplay(id);
a();
}
You can assign a function to a variable like so:
You can also return a function pointer from a function - see the return statement of findDisplay(id).
function treeItemClickHandler(id)
{
var a= findDisplay;
var other = a(id);
other();
}
function findDisplay(id)
{
return someOtherThing;
}
function someOtherThing()
{
}
Sure, functions are first class objects in JavaScript. For example, you can create a map (an object) which holds references to the functions you want to call:
var funcs = {
'id1': function(){...},
'id2': function(){...},
...
};
function treeItemClickHandler(id) {
if(id in funcs) {
funcs[id]();
}
}
As functions are treated as any other value, you can also return them from another function:
function findDisplay(id) {
// whatever logic here
var func = function() {};
return func;
}
functions are normal javascript values, so you can pass them around, (re)assign them to variables and use them as parameter values or return values for functions. Just use them ;) Your code is correct so far.
You can map between ids and functions to call in a number of ways.
One of the simpler ones is to create an object mapping ids to functions, and find the function to call from that object (this is in essence a nicer-looking switch statement).
Example:
function treeItemClickHandler(id)
{
var idMap = {
"some-id": findDisplay,
"another-id": doSomethingElse
};
if (!idMap.hasOwnProperty(id)) {
alert("Unknown id -- how to handle it?");
return;
}
// Call the corresponding function, passing the id
// This is necessary if multiple ids get handled by the same func
(idMap[id])(id);
}
function findDisplay(id)
{
// ...
}
function doSomethingElse(id)
{
// ...
}