unexpected "map" result (Javascript) [duplicate] - javascript

This question already has answers here:
Why does parseInt yield NaN with Array#map?
(8 answers)
Closed 3 years ago.
Can someone explain why this has the unexpected result:
["1", "2", "3"].map(parseInt);
which returns [1, NaN, NaN] instead of [1, 2, 3]?
I can make it work by forcing a single-argument function:
["1", "2", "3"].map(function(s) {return parseInt(s);});
but I don't know what exactly went wrong in the first way.

As others mentioned, the problem is due to the 2nd argument.
Comments from MDN:
// parseInt is often used with one argument, but takes two. The second being the radix
// To the callback function, Array.prototype.map passes 3 arguments: the element, the index, the array
// The third argument is ignored by parseInt, but not the second one, hence the possible confusion.
// See the blog post for more details
But, with the use of bind, you can achieve the desired result:
var _parseInt = function(radix, number) {
return parseInt(number, radix);
}
["1", "2", "3"].map(_parseInt.bind(this, 10));

parseInt takes two arguments (the second being the radix), that's why this doesn't work. See the bottom of this MDN page for more information. Cited:
parseInt is often used with one argument, but takes two. The second
being the radix To the callback function, Array.prototype.map passes 3
arguments: the element, the index, the array. The third argument is
ignored by parseInt, but not the second one, hence the possible
confusion.

this article describes your issue in its last sample, exactly the same what you are trying to do. However the blog article they refer to doesn't exist anymore.
array.map() and parseInt callback
A better answer cited from Stackoverflow:
So if you call a function which actually expects two arguments, the
second argument will be the index of the element.
In this case, you ended up calling parseInt with radix 0, 1 and 2 in
turn. The first is the same as not supplying the parameter, so it
defaulted to base 10. Base 1 is an impossible number base, and 3 is
not a valid number in base 2:
parseInt('1', 0); // OK - gives 1
parseInt('2', 1); // FAIL - 1 isn't a legal radix
parseInt('3', 2); // FAIL - 3 isn't legal in base 2

Related

the DOM doesn't work with me when I try min and max and it show NaN [duplicate]

I am trying to get the highest number from a simple array:
data = [4, 2, 6, 1, 3, 7, 5, 3];
alert(Math.max(data));
I have read that if even one of the values in the array can't be converted to number, it will return NaN, but in my case, I have double-checked with typeof to make sure they are all numbers, so what can be my problem?
The reason why your code doesn't work is because Math.max is expecting each parameter to be a valid number. This is indicated in the documentation as follows:
If at least one of arguments cannot be converted to a number, the result is NaN.
In your instance you are only providing 1 argument, and that 1 value is an array not a number (it doesn't go as far as checking what is in an array, it just stops at knowing it isn't a valid number).
One possible solution is to explicitly call the function by passing an array of arguments. Like so:
Math.max.apply(Math, data);
What this effectively does is the same as if you manually specified each argument without an array:
Math.max(4, 2, 6, 1, 3, 7, 5, 3);
And as you can see, each argument is now a valid number, so it will work as expected.
Spreading an array
You can also spread the array. This essentially treats the array as if each item is being passed as it's own argument.
Math.max(...data);
if you see doc for Math.max you can see next description
Because max() is a static method of Math, you always use it as Math.max(), rather than as a method of a Math object you created (Math is not a constructor).
If no arguments are given, the result is -Infinity.
If at least one of arguments cannot be converted to a number, the result is NaN.
When you call Math.max with array parameter like
Math.max([1,2,3])
you call this function with one parameter - [1,2,3] and javascript try convert it to number and get ("1,2,3" -> NaN) fail.
So result as expected - NaN
NOTE: if array with just one number - all work correctly
Math.max([23]) // return 23
because [23] -> "23" -> 23 and covert to Number is done.
If you want get max element from array you should use apply function, like
Math.max.apply(Math,[1,2,3])
or you can use the new spread operator
Math.max(...[1,2,3])
It's not working because you are passing an array as the parameter instead of comma separated numbers. Try spreading the array like this:
data = [4, 2, 6, 1, 3, 7, 5, 3];
alert(Math.max(...data));
If you have to use the Math.max function and one number of the array might be undefined, you could use:
x = Math.max(undefined || 0, 5)
console.log(x) // prints 5
You will need to use the spread operator while passing array as an argument to the Math.max() method.
alert(Math.max(...data)); //this should resolve it.

Bug in Array.prototype.includes?

I encountered strange behavior of Array.prototype.includes in one edge case.
Given that Array.prototype.includes works on bound context, one might use it like this (which is working)
expect(Array.prototype.includes.call([1, 2], 1))).toBe(true)
simply put, we bound array [1, 2] and test 1 for inclusion.
Then consider, that many Array.prototype methods are able to bound context to provided callback, so for example Array.prototype.some can be combined with Object.prototype.hasOwnProperty like this
expect(["foo", "bar"].some(Object.prototype.hasOwnProperty, { foo: 0 })).toBe(true)
Here, .some accepts two parameters, (callback, [thisArg]), where optional thisArg, when provided, is bound to callback, thus previous example binds { foo: 0 } to callback Object.prototype.hasOwnProperty and then tests all items in ["foo", "bar"] if at least one is own property of { foo: 0 }. This example is also working.
But something strange happen, if you try to use Array.prototype.includes as callback.
[0, 1].some(Array.prototype.includes, [1]) // => false
here we bind array [1] to Array.prototype.includes and we test every item of [0, 1] if at least one is included. But this case returns false, which is against our expectation.
Strangely, if bound array contains other number than 1 or contains more than one item, the test passes
[0, 1].some(Array.prototype.includes, [0]) // => true
[0, 1].some(Array.prototype.includes, [1, 1]) // => true
// but
[0, 1].some(Array.prototype.includes, [1]) // => false
It seems like array [1] is handled improperly.
Tested in
Node v.11.11.0
Node v.8.11.3
and Chrome 73
I tested basically just V8 engine. Can anyone report output in Chakra?
It's not a bug in includes. :-)
The problem is that includes accepts an optional second parameter, which is the index at which to start searching, and some provides three arguments to its callback: The item, its index, and the object being searched.
So with
[0, 1].some(Array.prototype.includes, [1])
These calls are made (effectively):
[1].includes(0, 0) - false, the array doesn't contain 0
[1].includes(1, 1) - false, the array contains 1 at index 0, but the search starts at index 1
This comes up periodically. For instance, when trying to use parseInt as a callback directly to convert an array of strings into an array of numbers, because of parseInt's second parameter (the number base, or radix, to use):
console.log(["6", "9", "7"].map(parseInt));
The 9 and 7 fail becaue the calls are (effectively):
parseInt("6", 0) - works because parseInt ignores the invalid radix 0.
parseInt("9", 1) - NaN because parseInt always returns NaN for radix 1
parseInt("7", 2) - NaN because "7" is not a valid digit in base 2 (binary)
The moral of the story: Remember the not-commonly-used arguments that map, some, forEach, and various other methods provide to callbacks. :-)
In one codebase I was working in, they had a clamp function that accepted a function and ensured that, regardless of how many arguments it was called with, it would only pass on the desired number of arguments. If you were using includes like this a lot, you could create a clamped includes:
function clamped(fn, count) {
return function(...args) {
return fn.apply(this, args.slice(0, count));
}
}
const includes = clamped(Array.prototype.includes, 1);
console.log([0, 1].some(includes, [1])); // true
console.log([0, 1].some(includes, [3])); // false
The handy thing about that is that that includes is reusable.
Or of course, just use a wrapper function:
console.log([0, 1].some(function(entry) {
return this.includes(entry);
}, [1])); // true
console.log([0, 1].some(function(entry) {
return this.includes(entry);
}, [3])); // false
These are all meant to be general solutions, of course. If you specifically want to know if array a contains any of the entries in array b, there are more specific implementations you can build to handle that efficiently depending on the characteristics of a and b.

splice(0) vs splice(0,undefined)

Splice with no second argument behaves as expected:
['a','b','c'].splice(0) // Returns ['a','b','c']
But Splice with a undefined second argument behaves differently:
['a','b','c'].splice(0, undefined) // Returns []
Can someone explain to me the difference? I would expect the same (first) result.
It suggests that internally, splice is using "arguments.length" or similar, to change its behaviour, rather than checking the arguments.
It suggests that internally, splice is using "arguments.length" or similar
Yes, that's exactly what happens internally.
If there is exactly one argument passed, it removes all elements until the end.
If there are more arguments passed, it takes the second one, casts it to an integer and uses it for the count of elements to be deleted. When you are passing undefined, it is cast to the number value NaN, which leads to the integer 0 - no elements are removed.
According to docs, Array.prototype.splice returns deleted elements.
It also says that when second parameter deleteCount equals 0 then nothing is deleted.
So, in the first case you are deleting everything after index 0 inclusive and the result is whole array.
In the second case you are deleting 0 elements and the result is empty array.
The reason the second result is empty is because, if the second parameter is 0 or negative, no elements are removed.
This is of course according to mozzila.
Syntax is:
splice(index, delete, insert)
There is condition actually "if delete part assigning "false" values which are (undefined, 0, false) it will return empty array".
That is why in second syntax returning blank array"
['a','b','c'].splice(0) //returns complete array
['a','b','c'].splice(0, undefined) // Returns []

How to make a radix is used on all parseInt() instances

The `parseInt() function can return undesired and/or unexpected results if the radix is not supplied.Please make a radix is used on all parseInt() instances.
how to edit it
please helpme
i will send file if you need it
The radix is the second parameter to the parseInt() function.
It sets the numerical base that should be used when converting the string to an integer.
Obviously you would expect parseInt('11') to always return 11 :)
This is not guaranteed by all various JavaScript implementations.
What is guaranteed though is that parseInt('11', 10) will always return that 11 that you'd expect "by instinct".
Choosing a different radix ( or working in an implementation that has a different default for that matter ) say 2 would mean that the number is interpreted relative to base 2 => parseInt('11') would actually mean parseInt('11', 2) and hence come out to 3.
Assuming you want to create an Error when a radix is not passed,
Shadow parseInt, keeping the old reference in a closure such as an IIFE
Test for your conditions
Invoke the old reference
For example
parseInt = (function (old_parseInt) {
return function parseInt(x, radix) {
if (arguments.length < 2)
throw new TypeError('parseInt must be given a radix');
return old_parseInt.apply(this, arguments);
};
}(parseInt));
Then in usage,
parseInt('12', 8); // 10
parseInt('12'); // TypeError: parseInt must be given a radix
(Running this code on this page will break stackoverflow, be warned)

Why is math.max() returning NaN on an array of integers?

I am trying to get the highest number from a simple array:
data = [4, 2, 6, 1, 3, 7, 5, 3];
alert(Math.max(data));
I have read that if even one of the values in the array can't be converted to number, it will return NaN, but in my case, I have double-checked with typeof to make sure they are all numbers, so what can be my problem?
The reason why your code doesn't work is because Math.max is expecting each parameter to be a valid number. This is indicated in the documentation as follows:
If at least one of arguments cannot be converted to a number, the result is NaN.
In your instance you are only providing 1 argument, and that 1 value is an array not a number (it doesn't go as far as checking what is in an array, it just stops at knowing it isn't a valid number).
One possible solution is to explicitly call the function by passing an array of arguments. Like so:
Math.max.apply(Math, data);
What this effectively does is the same as if you manually specified each argument without an array:
Math.max(4, 2, 6, 1, 3, 7, 5, 3);
And as you can see, each argument is now a valid number, so it will work as expected.
Spreading an array
You can also spread the array. This essentially treats the array as if each item is being passed as it's own argument.
Math.max(...data);
if you see doc for Math.max you can see next description
Because max() is a static method of Math, you always use it as Math.max(), rather than as a method of a Math object you created (Math is not a constructor).
If no arguments are given, the result is -Infinity.
If at least one of arguments cannot be converted to a number, the result is NaN.
When you call Math.max with array parameter like
Math.max([1,2,3])
you call this function with one parameter - [1,2,3] and javascript try convert it to number and get ("1,2,3" -> NaN) fail.
So result as expected - NaN
NOTE: if array with just one number - all work correctly
Math.max([23]) // return 23
because [23] -> "23" -> 23 and covert to Number is done.
If you want get max element from array you should use apply function, like
Math.max.apply(Math,[1,2,3])
or you can use the new spread operator
Math.max(...[1,2,3])
It's not working because you are passing an array as the parameter instead of comma separated numbers. Try spreading the array like this:
data = [4, 2, 6, 1, 3, 7, 5, 3];
alert(Math.max(...data));
If you have to use the Math.max function and one number of the array might be undefined, you could use:
x = Math.max(undefined || 0, 5)
console.log(x) // prints 5
You will need to use the spread operator while passing array as an argument to the Math.max() method.
alert(Math.max(...data)); //this should resolve it.

Categories

Resources