i'm trying to create a function that take an array as an argument, and return "true" only if all the items inside the array are the same .
i try to use for loop and i try to use forEeach loop
the first one work great.
the second one not!.
why?
this my first code:
function isUniform(ary) {
var first = ary[0];
for (i = 0; i < ary.length; i++) {
if (first !== ary[i]) {
return false;
}
}
return true;
}
console.log(isUniform([1, 2, 1]));
this my second one:
function isUniform(ary) {
var first = ary[0];
ary.forEach(function(element) {
if (first !== element) {
return false;
}
});
return true;
}
console.log(isUniform([1, 2, 1]));
5 Answers 5
The "inner" return in your second example is a return from the function passed to forEach. It does not cause an immediate return from the isUniform function. Instead, this little anonymous function you passed to forEach runs happily to completion for every single element of your array.
After it finishes running through all of the elements, your isUniform function then simply returns true.
Comments
By returning true you are returning true to the forEach function callback while you're for loop returns true to the function. Your forEach requires a reference object when executing a callback if you want to use your current approach. That is how it is different from your for loop.
function isUniform(ary) {
var first = ary[0];
val = true;
ary.forEach(element => {
if (first !== element) {
val = false;
}
});
return val;
}
console.log(isUniform([1, 1, 1]));
console.log(isUniform([1, 2, 1]));
There is already an every function you can take advantage of.
arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
arr2 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
console.log(arr1.every((a, _, aa) => aa[0] === a));
console.log(arr2.every((a, _, aa) => aa[0] === a));
6 Comments
val you should really stick to the lexical closure, just as you do with first. Bringing this into the picture pollutes the context and also makes the code confusing to read.forEach is not a conditional construct, and it does not care/check/forward/store/accumulate/etc. whatever the called function returns. If one really wants to break from a forEach loop, throwing an exception can do that, but it is not a nice solution.You can't break from a forEach.
Try this one. You can do it with the flag.
var falg = false;
function isUniform(ary) {
var first = ary[0];
ary.forEach(function(element) {
if (first !== element) {
falg = true;
return false;
}
});
if(falg)
return false
return true;
}
console.log(isUniform([1, 2, 1]));
Comments
The how part has been addressed in @Arrow's post already, if you work with forEach, it does not care about the return values, you have to accumulate the result yourself (also, there is no 'normal' way of breaking out from the loop, though you could throw an exception if you really want to).
For the 'why' part: because of definition. forEach does not care about return values and runs the passed function for all elements, unconditionally.
A simplified implementation of forEach is the following:
Array.prototype.myForEach=function(callback){ // or callback,diz
for(var i=0;i<this.length;t++)
callback(this[i],i,this); // or callback.call(diz,this[i],i,this);
}
The result of callback is completely ignored. (Commented parts add support for the optional context-argument)
A 'more official' polyfill does some extra checks, but it is not complicated either: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Polyfill
Comments
can you try this, change the var element for x, and use lambdas
function isUniform(ary) {
var first = ary[0];
ary.forEach((x) => {
if(first !== x){
return false;
}
});
return true;
}
forEachand return of an inner closure doesn't return to the outer one