As part of an exericse, I'm re-writing underscore functions and testing them in jsfiddle. Every time I pass a callback function, I get "undefined".
My code is below:
each = function(collection, iterator) {
if(Array.isArray(collection)){
for (var i = 0; i < collection.length; i++) {
iterator(collection[i], i, collection);
}
} else {
for(var key in collection) {
iterator(collection[key], key, collection);
}
}
};
var numbers = [1,2,3,4];
var result = each(numbers, function(num) {
return num * 2;
});
console.log(result);
// undefined
Any idea what I'm doing wrong and why it's not outputting on jsfiddle?
You aren't doing anything wrong. Your each function isn't returning anything. This is fine, since each functions don't necessarily have to return anything. You might be thinking along the lines of a map or reduce function which compile the results of calling the callback on each item in the collection, and then return that compilation.
The callback you pass to an each function doesn't normally return anything. Think of an each like it's just syntactic sugar for a normal for loop; for loops don't return anything (obviously..), they just perform generic operations with the items in the collection and the variables that have been declared in the containing scope.
That being said, if you want to emulate underscore (or any good library), you will want to return the collection to enable chaining. From the underscore docs:
[each] Iterates over a list of elements, yielding each in turn to an iteratee function....Returns the list for chaining.
This is just good practice so as to avoid annoying the developers who may use your library and are used to being able to chain everything in JavaScript.
So all you'd need to do is put
return collection;
at the end of your each function and you're good. Cheers.
You are not aggregating the result of your operation that's why the result is not being result.
Here is a quick stab at how this can be fixed for arrays.
each = function(collection, iterator) {
var arr = [];
if(Array.isArray(collection)){
for (var i = 0; i < collection.length; i++) {
arr.push( iterator(collection[i], i, collection) );
}
return arr;
} else {
for(var key in collection) {
iterator(collection[key], key, collection);
}
}
};
var numbers = [1,2,3,4];
var result = each(numbers, function(num) {
return num * 2;
});
console.log(result);
jsfiddle
Related
In Eloquent JavaScript, 1st ed, page 77, it gives an example of building a mapping function from scratch:
function mapFunc(func, array) {
var result = []; // not touching the original!
console.log("array:", array)
forEach(array, function(element) {
result.push(func(element));
});
return result;
}
Seems pretty straightforward but when it's run like this:
console.log(mapFunc(Math.round, [0.01, 2, 9.89, Math.PI]))
It throws an error:
ReferenceError: forEach is not defined
Even when I change things up to match the es6 syntax more, same issue:
array.forEach(function(element) {
result.push(func(element))
console.log(element)
})
I've been messing with it for a while and can't figure out what the problem might be or why forEach suddenly becomes undefined. Thoughts?
You need to use array.forEach, and you need to call mapFunc() correctly. You're passing the array as the second argument to console.log() rather than mapFunc().
function mapFunc(func, array) {
var result = []; // not touching the original!
console.log("array:", array)
array.forEach(function(element) {
result.push(func(element));
});
return result;
}
console.log(mapFunc(Math.round, [0.01, 2, 9.89, Math.PI]));
The book defines a forEach() function of its own earlier in the chapter.
function forEach(array, action) {
for (var i = 0; i < array.length; i++)
action(array[i]);
}
If you add that function to your code, you should be able to use the mapFunc() function as you first wrote it. But you need to call mapFunc() correctly in either case.
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);
Is there a way that i could call a Async Method in a loop, put all the results in a array & return the results in the end.
Pseudo Code of what i want to do:
methodThatRunsAsync(callback){
once completes, invoke callback;
}
anotherMethod (){
var result = [];
for(i=1; i=10; i++){
methodThatRunsAsync(function(resp){
result.push(resp);
});
return result; }
}
But the value of result is always the default value. How can i trap the results of the async block in a sync block and return the same to the caller.
Looking into Promise framework, but finding it a bit tough to get my head around it. If anyone can please help me understand how to achieve this, psuedo code too would be great.
No, you can't return the result, as the calls as asynchronous. Use a callback for that function too, and call it when the last result is added:
function anotherMethod (callback) {
var result = [];
var count = 10;
for(i = 0; i < count; i++) {
methodThatRunsAsync(function(resp){
result.push(resp);
if (result.length == count) {
callback(result);
}
});
}
}
Note that I changed the loop. The loop that you had would not do any iterations at all.
I am learning Javascript for a project using online resources however i don't know how to get this function working.
var results =[[a1,a2,a3,a4,a5]];
var winner = 0;
function checkWinner (results)
{
for (var i = 0; i < results.length; i++)
if (results[0][i] > 50)
{
winner = results[0][i];
}
}
Just after the function, i use:
checkWinner(results);
In a HTML file i use alert to display the variable winner. But it obviously doesn't work. I realise it is a problem with my understanding of scope and global variables.
should be
var Results =[[a1,a2,a3,a4,a5]];
var winner = 0;
function checkWinner (results)
{
for (var i = 0; i < results[0].length; i++)
if (results[0][i] > 50)
{
winner = results[0][i];
}
}
checkWinner(Results);
To avoid name collisions name global variables from capital case.
Also in your code you call the length of the "parent" array. You need to specify the length of the "Child" array
You've got to understand the concept of scope. The variables results and winner are not the same inside and outside the function.
Also, you've got to call the function and return something from it if you want to change the value of the variables outside the function (unless you use globals). This seems to be hard for novice programmers to understand, but merely defining a function doesn't do anything.
var results =[[a1,a2,a3,a4,a5]];
function checkWinner (results)
{
for (var result in results[0])
{
if (result > 50)
{
return result;
}
}
}
var winner = checkWinner(results);
Note that:
I used a for each loop, which has a cleaner syntax.
I am also iterating over results[0] instead of results, since you've got a nested array for whatever reason.
Because your function has an argument called results, it requires you to pass the global results in spite of it being a global. Another way to do this:
var results = [[a1,a2,a3,a4,a5]];
function checkWinner()
{
for (var result in results[0])
{
if (result > 50)
{
winner = result;
return;
}
}
}
checkWinner();
However, I would recommend against using global variables this way. Here's an explanation on why global variables are bad. It's for C++, but it applies to JavaScript as well.
You're iterating over the result[0] array (the array in result[0]), but using the length of the result array.
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
}
}