Getting undefined instead of a correct result - javascript

I am trying to use forEach method on my array but I am getting undefined instead of a correct result. Could anyone help me and tell me what is wrong with my code?
[0,1,2,3].forEach((x,i) => (x*i)%3);

The return value of forEach() is undefined, use Array.prototype.map() instead:
var r = [0,1,2,3].map((x,i) => (x*i)%3);
console.log(r);

You're using forEach, which doesn't return anything, so the result of calling it is undefined. (forEach also completely ignores the return value of the callback it calls.)
If you want a return value, you probably want map (or possibly reduce), not forEach. For example:
console.log([0,1,2,3].map((x,i) => (x*i)%3));

You're returning nothing inside the forEach, write a console.log for that

This is from https://developer.mozilla.org/
forEach() executes the callback function once for each array element; unlike map() or reduce() it always returns the value undefined and is not chainable. The typical use case is to execute side effects at the end of a chain.
If you are trying to transform the array, use map() instead

Related

What is the use of ,[] in an anonymous function called?

I was doing a coding challenge which takes in either a one or two dimensional array and then returns a flattened array. After writing my code I looked on the forums to see how others wrote theirs and found an interesting answer.
function flattenArray(array) {
return array.reduce((acc, cur) => acc.concat(cur), []);
}
Note at the end of the return line, he used ,[] after the concat. I tried to break it down to see if I could understand that last part but I am unable to throw {} around it without it throwing me an error.
function quickFlatten(array)
{
return array.reduce((acc, cur) => {
acc.concat(cur), [];
});
}
When this is called I am given a TypeError:
TypeError: acc.concat is not a function
What is ",[]" , how does it work and how can I learn more about what he did? It appears to make acc an array but only works when there are no {} in the anonymous function.
This is the initial value of the accumulator (called acc here) use by the reduce function.
Reduce builds up a value by iterating over an array and returning it for the next iteration. The initial value has to come from somewhere, and it comes as a second parameter of the reduce function :)
you should probably read this : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

confused on the combination of Array.isArray() and every()

I am trying to check every element within the target object is an array object by using the every()function, the code as follows:
let targetObj = [[1,2],[3],4];
let result = targetObj.every((val,index,arr)=>{
return Array.isArray(val);
});
the resultis false because 4 is not an array object, but i found if i replace the callback function with Array.isArray which is still work:
let result = targetObj.every(Array.isArray);
So my questions are:
1.In this way, since the callback function is not taking any parameters.Why the result still return false?
2.How the Array.isArraycallback function can automatically check every element from targetObjwithout gave any parameters?
Array.isArray has one param.
.every( ... ) gives 3 params.
A callback in .every (without calling it directly) is going to give params.
If the callback has more than 3 params, the next params are gonna be undefined.
Since you're not calling the callback, .every is calling it for you and it's gonna fill its params.

Javascript: Adding a property to an array of objects

I have an array of objects as follows:
var myarray=[{"name":"John","address":"home"},{"name":"Peter","address":"home"}]
and I would like to run a function to add a property to the array as follows:
[{"name":"John","address":"home","collection":"friend"},
{"name":"Peter","address":"home","collection":"friend"}]
I have tried doing this:
myarray=myarray.map(function (err, myarray){
myarray.collection="friend";
return myarray;
}
console.log(myarray)
But the console continues to return this:
[{0},{1}]
Can anyone help me? Thank you
Your code is not adding the property to the contents of the array. The values of the array are given as the first parameter to the callback function (the second parameter is an index, and not the array itself—that's the third parameter). Simply assign the new property to the first parameter of the callback function, rather than the second one.
Edit - As #zerkms points out, however, if you're looking to update the current array rather than generate a new array, map is probably not best solution here. forEach provides a method for iterating over the current array, and modifying each of its values (which is what you're doing). This would looks omething like this:
myarray.forEach(function(value) {
value.collection = "friend";
});
As you'll notice in the documentation for .map, the callback function returns the new value that will appear in the new array that is generated by map; if you're changing the current array in place (i.e. by modifying the properties of its contents), there's no need to return anything.
myarray.map(function(value) {
value.collection = "friend";
});
Also note that both map and forEach are methods, so you need to close the method invocation with ).
Wrong use of map().
The first argument of map() is the current element of the array, the second argument is it's index.
For example:
['a','b','c'].map(function(element, index){console.log(element, index)});
Will result in
a 1
b 2
c 3
So inside your function myarray was your index, and you were trying to add the property to the index.
Now you have to options. Either you use the map() as it's ment to be used and assign it's return value to myarray:
myarray = myarray.map(function(element) {
element.collection = "friend";
return element;
});
or you can, because objects are not getting copied but referenced when passed as an argument, not care about the return values and modify the elements directly:
myarray.map(function(element) {
element.collection = "friend";
}); // returns [undefined, undefined ...]
This, however, isn't the way one should use map()
Better: Use forEach()
myarray.forEach(function(element) {
element.collection = "friend";
});
Hope it helped.
Greets!
All you have to do is changing the reference object within map function
myarray.map(function (value){
value.collection = "friend";
});
console.log(myarray);

Why can't I chain String.prototype.toLowerCase with underscore.js?

I think the issue is not with underscore.js, but rather with Native prototypes functions. It seems that one can only call them directly, not passing them as callbacks. Here's the code the I can't use and the error from my tests (using Mocha.js, only the relevant portion):
_.chain("INPUT").tap(String.prototype.toLowerCase)
// => TypeError: String.prototype.toLowerCase called on null or undefined
So tried this in Node's REPL :
String.prototype.toLowerCase("INPUT")
// => ''
I know one should call a prototype's function with .call or .apply, but why exactly ? And how can I pass this function as a callback ?
Prototype methods are using this internally to refer to the object that should get manipulated.
call and apply lets you specify the this value when calling a function.
String.prototype.toLowerCase.call('INPUT'); //input
If you want to bind a this value to a function so that it's invocation form doesn't matter, you can do it with _.bind or Function.prototype.bind.
var lowerCaseInput = String.prototype.toLowerCase.bind('INPUT');
lowerCaseInput(); //input
Now, calling _.chain on an object will wrap it in an underscore object and returns the wrapper and _.tap takes the result of the previous function in the chain as it's input. Right here we see it's not going to work since String.prototype.toLowerCase doesn't even expect arguments.
Not only this, but strings are immutable so you would have to do something like the following:
_.chain({ text: 'INPUT' }).tap(function (obj) {
obj.text = obj.text.toLowerCase();
}).value().text;
Additionally, if you use mixins, you can use a mixin that simply wraps toLowerCase.
_.mixin({
toLowerCase: function(str) {
// Add here any desired validation if wanted
return str.toLowerCase();
}
}, {
chain: false
});
After, you can do something like:
_.chain('HELLO_WORLD')
.toLowerCase()
.replace('_',' ')
.value()

a few questions when iterator the arraylike object in javascript

In my application,I need to do some iteration with the array-like object.
So I write a custom util method:
Util.forEach=function(iterator,callback,context){
if(iterator.length){
for(var i=0;i<iterator.length;i++){
var val=iterator[i];
callback && callback.call(context||null,val,i);
}
}
}
Then I meet some problems:
Suppose I have an array: var ary=[1,2,3,4,5];
1. how to break the loop?
For example, if I want to find if value '2' is included in the array,I may try this:
Util.forEach(ary,function(value,index){
if(value==2){
//find mached value,now I should break and return this value.
//but I can not use 'break' in this context.
}
});
2. remove value of the array when iterator
If I want to remove value '2' of the array,I may try this:
Util.forEach(ary,function(value,index){
if(value==2){
//delete it.
ary.splice(i,1);
// I wonder if this is the safe way?
}
});
Since in java we can not do this when iterate an array,it will cause the concurrency exception.
Though I run the above code without any error,but I am not sure if it is the best practice?
Generally, you can break out from a forEach-like method by using try-catch and throw.
var value = 'Not Found';
try {
Util.forEach(ary, function(value, index) {
if(value == 2) {
throw value; //<-- Throw the found result: Terminates current forEach
}
});
} catch (found) { // Catch the thrown result
value = found;
}
The first issue can be solved by checking the return value from the callback and stopping the iteration if it returns false. Then you can stop the iteration by returning false from the callback. Returning anything other than false (including returning nothing) will continue the iteration. jQuery uses this return value technique to cancel the iteration in their .each() iterator. Adding that into your code, it would look like this:
Util.forEach=function(iterator,callback,context){
if (iterator.length && callback) {
for(var i = 0; i < iterator.length; i++){
var val=iterator[i];
if (callback.call(context||window,val,i) === false) {
break;
}
}
}
}
In the MDN documentation for forEach, you can see a sample implementation.
On the second issue, this type of implementaation does not permit insertion or deletion of elements at or before the iteration point because that will cause some elements to get skipped in the iteration or some objects to get iterated multiple times. The obvious way around that would involve making a copy of the object before iterating which is not efficient when not needed.
how to break the loop?
You're not supposed to break from forEach. That's why it's called "for each", and not "for some". "Breakable" JS iterators are every() (stops when the callback returns false) and some() (stops when the callback returns true).
Looking at your code once again it makes me think you actually want an indexOf kind of method, and not an iterator.
remove value of the array when iterator
Iterators shouldn't make any changes of the underlying array. You have to implement filter() and use it to generate a new array.
See js iteration methods for more details.

Categories

Resources