Consider the code snippet below:
function isUniform(myArray) {
myArray.forEach(function(element) {
if (element !== myArray[0]) {
return false;
}
});
return true;
}
The intention is that the function should take an array as input and return true if all the elements in the array are the same and false otherwise.
eg:
isUniform([1,2,1,1]); // should return false
isUniform([1,1,1,1]); // should return true
However, the if condition:
if (element !== myArray[0])
never seem to be true in the case of isUniform([1,2,1,1]).
What is it that I am missing ?
So the return true isn't returning a value for the function isUniform, it's returning a value for the callback that you provided to the forEach method. forEach is really only used to create side effects. So forEach executes the callback on each element, sees that the callback returns false, but then doesn't have anything to do with that value, so it throws it out and moves on to the next element in the array. After iterating through the array, it moves on to the next line of code and returns true for the function.
One way that you might do this using forEach is to declare a variable that you initialize as true and manipulate that within the callback. This is necessary, as there's not a way to end the execution of a forEach loop early. So you might instead use:
function isUniform(myArray) {
var passing = true;
myArray.forEach(function(element) {
if (element !== myArray[0]) {
passing = false;
}
});
return passing;
}
Or you could use a for loop or a for-of loop, in which case the return statement would work as you had originally expected. You're probably already familiar with for loops. For-of loops were introduced in ES2015 (so they might not work on all JS engines). A for-of loop would look like this:
function isUniform(myArray) {
for (element of myArray) {
if (element !== myArray[0]) {
return false
}
}
return true
}
However, the best way to do this is probably using the built in array method every, which returns true if every element in the array passes the test provided in the callback. So you might test every element to see if they're equal to the 0th element in the array and thus equal to each other:
function isUniform(myArray) {
return myArray.every(function (currentElement,index,array) {
return currentElement === array[0]
})
}
That's short enough that you really don't even need to put it in its own function -- and your code will probably be more readable if you don't.
Docs:
Array.prototype.every: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every
For-of loop: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
Related
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]);
}
}
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?))
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;
}
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'm trying to learn coding in Javascript and came across this question and have a few questions. What does results.push.bind(results) do in this question? Please see question below:
Suppose getData is a function that takes a query object and returns a promise for the result of the query. Suppose also that someArrayOfQueries is an array of query objects. Explain what would be printed by the following code and why:
function runMultipleQueries(queries) {
var results = [];
queries.forEach(doQuery);
return results;
function doQuery(query) {
getData(query)
.then(results.push.bind(results));
}
}
function log(value) {
console.log(value);
}
runMultipleQueries(someArrayOfQueries).forEach(log);
In Javascript, unlike in other Object Oriented languages, the variable this is quite complicated and can be changed many times.
When working with arrays, the function push takes the array it is called "on", and puts a new element to the end of it. In this case, the push function knows what array it is working on by reading the this variable.
Imagine this example code:
var myDataStructure = {};
myDataStructure.value = 0;
function addOneToValue() {
this.value += 1;
}
myDataStructure.addOne = addOneToValue;
myDataStructure.addOne(); // here - the variable `this` == myDataStructure
However, if you call the function addOneToValue with the code addOneToValue(), the value of this is not in fact myDataStructure. It is undefined, or a global object like window.*
To manually force addOneToValue to always use myDataStructure as the this value, you can do the following:
addOneToValue = addOneToValue.bind(myDataStructure);
Now you can safely call addOneToValue(), since the this value was bound to myDataStructure.
In your code, runMultipleQuery is passing the function to another handler, who will not call the function like results.push. That means when the function is called, push will again have an uncertain this value. However, by calling bind, we can ensure that runMultipleQuery calls the push function and forces this to be the results variable.
What results.push.bind(results) does is it forces the method call of push to use the scope of results.
TLDR;
results is an Array. results.push() is a call to Array#push, but by passing the function results.push directly to the Promise Promise#then it will be called within a different scope.
That is, the keyword this will reference a different object.
By using bind (e.g. - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind), the scope will be "bound" to a specific Object.
The reason for this is because JavaScript is a prototype language, rather than an object-oriented language.
What does .push.bind do?
Returns the .length of the array, when called
function runMultipleQueries(queries) {
var results = [];
return Promise.all(queries.map(doQuery));
function doQuery(query) {
return Promise.resolve(query)
.then(results.push.bind(results))
}
}
function log(value) {
console.log(value);
}
runMultipleQueries([10, 20, 30]).then(log);
Note, that as astutely observed and alerted to by #Bergi, the pattern .then(results.push.bind(results)) actually returns the .length of the array.
One solution which still includes the use of the pattern is to chain a second .then() to get the .length returned by previous .then() and return the element of the array by subtracting 1 from the value and using bracket notation
function runMultipleQueries(queries) {
var results = [];
return Promise.all(queries.map(doQuery));
function doQuery(query) {
return Promise.resolve(query)
.then(results.push.bind(results))
.then(len => results[len - 1]);
}
}
function log(value) {
console.log(value);
}
runMultipleQueries([10, 20, 30]).then(log);
though creating results array is not necessary when using Promise.all(), which returns an array of values
.forEach() alone will not await the previous result of getData() call, results will probably be an empty array at runMultipleQueries(someArrayOfQueries).forEach(log);
Use Promise.all() and .map() instead of .forEach(), return the Promise from getData() call
function runMultipleQueries(queries) {
return Promise.all(queries.map(doQuery));
function doQuery(query) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(query)
}, Math.floor(Math.random() * 1000))
})
}
}
function log(value) {
console.log(value);
}
runMultipleQueries([1,2,3]).then(log);
"Illegal break statement" is appearing. Can anyone suggest the reason to solve it
this.selectOrganization = function() {
organizationLocator.each(function(element) {
FunctionLibrary.getText(element, organizationName).then(function(text) {
logger.info(text);
if (text.includes('ImageResizingOrg')) {
FunctionLibrary.click(element, organizationName);
break;
}
})
})
};
organizationLocator.each(function(element) {
FunctionLibrary.getText(element, organizationName).then(function(text) {
logger.info(text);
if (text.includes('ImageResizingOrg') && temp == true) {
FunctionLibrary.click(element, organizationName);
temp = false;
}
})
})
You can't break from the each method—it emulates the native forEach method's behavior, and the native forEach doesn't provide to break the loop other than throwing an exception.
See the quote from mozilla doc:
There is no way to stop or break a forEach() loop other than by throwing an exception. If you need such behavior, the forEach() method is the wrong tool.
Early termination may be accomplished with:
A simple loop
A for...of loop
Array.prototype.every()
Array.prototype.some()
Array.prototype.find()
Array.prototype.findIndex()
The other Array methods: every(), some(), find(), and findIndex() test the array elements with a predicate returning a truthy value to determine if further iteration is required.
But there is a solution of it which isArray.every method, which uses it's callback's return value to iterate over next element.
every executes the provided callback function once for each element present in the array until it finds one where callback returns a false value. If such an element is found, the every method immediately returns false.
Example of Array.every method:
var orgs = ['NSO', 'CRY India', 'WHO', 'ImageResizingOrg', 'Unicef'];
var returnval = true;
orgs.every(function (text) {
if (text.includes('ImageResizingOrg')) {
//you can do anything here like firing click event as you have done in your code
returnval = false;
}
console.log(text);
return returnval;
});
Use Promise.all to combine each iteration of the for each loop and reject the promise when you wish to break out of the loop.
var promises = [];
organizationLocator.each(function(element) {
promises.push(FunctionLibrary.getText(element, organizationName).then(function(text) {
logger.info(text);
if (text.includes('ImageResizingOrg')) {
FunctionLibrary.click(element, organizationName);
return Promise.reject(false);
}
}));
});
return Promise.all(promises);
I have a JavaScript function as:
function nodeExists(text, ancestor, tree, generationCount) {
tree.findByText(text).each(function (index, element) {
var gen = generationCount;
var currNode = element;
while (gen !== 1) { // 1: node itself
currNode = tree.parent(currNode);
gen--;
}
if (tree.text(currNode) === ancestor)
return currNode; // Even if condition is met, control continues looping
})
return null;
//return ($.inArray(ancestor, gArr) !== -1) ? true : false;
}
While debugging function not exiting from a loop even if tree.text(currNode) === ancestor is truthy. Is Jquery .each causing it. Please help me.
From the jQuery documentation:
We can break the $.each() loop at a particular iteration by making the
callback function return false. Returning non-false is the same as a
continue statement in a for loop; it will skip immediately to the next
iteration.
You aren't returning false so the loop will continue.
Did you try an alert instead of a return ? Perhaps your ancestor is not "===" but just "==" to your tree.text(currNode) ?
You will have to return 'false'. Otherwise, it will go to next iteration.
I am at the end of the modules chapter, but I don't really understand the whenDepsLoaded() part of this code. Could someone explain it for me please?
for example, what does this line do?
if (!deps.every(function(m) { return m.loaded; }))
return;
And this line?
myMod.onLoad.forEach(function(f) { f(); });
var defineCache = Object.create(null);
var currentMod = null;
function getModule(name) {
if (name in defineCache)
return defineCache[name];
var module = {exports: null,
loaded: false,
onLoad: []};
defineCache[name] = module;
backgroundReadFile(name, function(code) {
currentMod = module;
new Function("", code)();
});
return module;
}
function define(depNames, moduleFunction) {
var myMod = currentMod;
var deps = depNames.map(getModule);
deps.forEach(function(mod) {
if (!mod.loaded)
mod.onLoad.push(whenDepsLoaded);
});
function whenDepsLoaded() {
if (!deps.every(function(m) { return m.loaded; }))
return;
var args = deps.map(function(m) { return m.exports; });
var exports = moduleFunction.apply(null, args);
if (myMod) {
myMod.exports = exports;
myMod.loaded = true;
myMod.onLoad.forEach(function(f) { f(); });
}
}
whenDepsLoaded();
}
for example, what does this line do?
if (!deps.every(function(m) { return m.loaded; })) return;
It checks if there is at least one dependency that has not been loaded.
Array.prototype.every() basically iterates over the whole array and invokes the "test" function that you pass to it. In this example, it check if an object has loaded property set to a truthy value. But because there is a negation in from of that every call, it means that if not every dependency has been loaded, it will return from the function.
And this line?
myMod.onLoad.forEach(function(f) { f(); });
Since mod.onLoad contains an Array of functions, it simply invokes these functions one by one.
You should look at Array.prototype.forEach() documentation.
Work step by step from the inside out
Start at the inside of the puzzling statement and work outwards. That way there is less to think about at each stage.
if (!deps.every(function(m) { return m.loaded; })) return;
The innermost part is function(m) { return m.loaded; }. This is a function that takes an object and returns its "loaded" property, i.e. whether it is loaded.
The .every function takes an array and only answers true if all the elements in the array pass the test inside the parentheses.
Therefore deps.every( ..... ) takes the deps array and tests all its elements, for the presence of the ".loaded" property being true. If all of them are true, which means in practical terms that all the dep[endencie]s are loaded, then deps.every... is true.
By making the if statement test for !deps.every, that statement is looking to see if ANY of the deps are NOT loaded, and if so the entire function returns at that stage.
myMod.onload
myMod.onLoad.forEach(function(f) { f(); });
Here, function (f) { f(); }; is defining an anonymous function whose input is another function, and which executes that (other) function. For example, if you pass the anonymous function an input of console.log("hello"), it will print "hello" to the console.
myMod.onLoad is a list of functions that are designed to be run when the module loads. myMod.onLoad.forEach() is a way of iterating automatically over all of those functions, and feeding them into the anonymous function described above, which arranges for those functions to be executed.
The overall effect is that the statement scans through all the functions listed in myMod.onLoad, and executes them.