I've seen people using regex, typeof or some built-in function like isNaN; to check if a variable / object's property is number or not.
But then today I found a "hack":
if(a.x*1) {
//a.x if a number
} else {
//a.x is not a number; a.x*1 is NaN
}
I'm just wondering if there is any downside to this trick.
Edit: I can't control the value of a.x, but I know it's either a number (1.2), a string("error") or a string that can be coerced to a number ("1.2"). I need a fast and clean way to both check its validity and convert it into a number.
Edit2: What if I check with a.x*1!==NaN?
Your check will incorrectly claim 0 isn't a number, so no, it isn't a replacement for isNaN or similar.
Note that if you want to know if a.x is already a number (and not something that can be coerced to a number), even isNaN isn't the right tool, since it will report that "12" is a number, or that any date instance is. To check if it's already a number (rather than something that can be coerced to one), you need typeof. (Of course, typeof NaN is "number", so you have to allow for that, too.)
So if you want to know if a.x is already a number and isn't NaN:
if (typeof a.x === "number" && !isNaN(a.x))
If you want to know if it's a number or something that can be implicitly coerced to a number that isn't NaN:
if (!isNaN(a.x))
Multiplying someVariable by 1 will cause implicit conversion to a number. This is the same as doing someVariable - 0 or +someVariable or the explicit Number(someVariable).
One downside to using the proposed method is that using a unary plus (+) or calling Number as a version for the conversion is idiomatic in JavaScript, which means it's well understood, so using another method to achieve the same can be confusing and make your code harder to read.
However, there is another aspect - the result of all of those conversions would not accurately tell you if the value was a number or not. Consider the following:
function isNumber(someVariable) {
if(someVariable*1) {
console.log(`"${someVariable}" is a number. For real: ${typeof someVariable}`)
} else {
console.log(`"${someVariable}" is not a number. It was a ${typeof someVariable}`)
}
}
//these are correct
isNumber(1);
isNumber("abc");
//these are incorrect
isNumber(0);
isNumber("123");
isNumber(" 321");
isNumber([1]); //logged as simply *1* the string value of an array with with one element is that element
var obj = {
name: "Fred",
age: 42,
valueOf: function() {
return this.age;
}
}
//this is also incorrect
isNumber(obj)
Checking the result of some operation would, by definition, tell you about the result of that operation. So, checking if something can be implicitly converted to a number by examining the result would tell you exactly that - the source could be implicitly converted to a number.
Furthermore, when doing if (resultOfImplicitConversion) you are checking if that result is truthy or falsey. That's not the same as checking it's type.
So, the pitfalls of your proposed method is that it is inaccurate in both steps of its attempted verification, and it also possibly inaccurately presents your intentions to future readers of your code (including yourself).
If you want to check if a value is a number, then follow this great answer on StackOverflow
Related
Is there any way to detect - or safely guard against - NaN values during runtime, across any part of the application where these might appear?
A) Is there a safe linting to warn about potential NaN values that might occur in certain constructs?
B) Alternatively, some kind of solution that monitors the executed JavaScript during runtime, detects and logs or alerts about it? - Similar to how error detection services work?
Example
Pseudo-code of a scenario where testing for NaN might be hard:
function undetectedNaN (): AssumeStrictDataTypes {
// 1. Some algorithm ...
// 2. NaN appears undetected ...
// 3. Some algorithm ...
// 4. Return: Broken but seeming legit value and data type
}
(Assume that it's in a larger application codebase, where adding checks for isNaN() and validating individual values is not an option: It might be too costly, not a requirement, no automated testing possible etc. ...)
UPDATE 2021/12: To complement my rather abstract question: In a more practical use case, API values did not exist in an array structure. Most occurrences of NaN could be solved by better value/type checking.
function example (a, b) {
return a[0] + b[0]
}
// undefined + undefined = NaN
const result = example([], []);
console.log(result);
Some other possibilities of NaN occuring:
const testArray = [];
const testObject = {};
testArray[0] + testArray[0] // NaN
testObject.X + testObject.X // NaN
undefined + undefined // NaN
NaN + NaN // NaN
Other places where NaN might be harder to track:
e.g. if it appears during runtime, somewhere, sometimes, and is not a testable return value.
// Bitwise operators
~(NaN) // -1
// Conditionals
if (NaN > 1) {} // false
// Typecasting
!!NaN // false
There is no simple way to achieve this.
There is no easy way of detecting this statically (for a linter). NaN can be a result from simple operations like multiplication and division, so it could occur anywhere.
Of course it would be technically possible to detect expressions that always evaluate to NaN, such as if you were to type 0/0. But this is probably not what you're looking for.
To my knowledge there is no framework that can detect NaN occuring somewhere at runtime. I believe that to achieve this in the way that you want, you would need support for it at JS engine level.
You could invent hacky solutions like creating functions for arithmetic operations like multiply or wrap numbers in objects that override the valueOf() function. But none of them will work in every case and they make your code a lot less pleasant.
In the end NaN is a perfectly valid number. You would detect it like you would detect any other value. For example, if your algorithm couldn't handle negative numbers, you also couldn't bend the language so it tells you when you have negative numbers. Instead you would have to design your code in such a way that negative values don't occur or you write a lot of checks/assertions.
Can someone ask me why Number.isFinite dont have type guard like number is number?
THis example provides an error Object is possibly 'undefined'
function inc (n?: number) {
return Number.isFinite(n) ? n + 1 : 1;
}
Playground:
https://www.typescriptlang.org/play?ssl=1&ssc=1&pln=3&pc=2#code/GYVwdgxgLglg9mABDSiAUYD8AuRYQC2ARgKYBOAlIgN4BQiiZJUIZSAcoaWQHQwDOAMRQwoJDFUx5EAakQBGRLnkBuWgF8gA
First some background. On first glance, this seems to be related to the difference in JavaScript between
isFinite
which will first convert its argument to number and
Number.isFinite
which happily accepts all arguments, regardless of type, and simply returns true only for finite numbers (with no implicit conversions). In TypeScript these have signatures
function isFinite(number: number): boolean
(method) NumberConstructor.isFinite(number: unknown): boolean
In the second method, the parameter type is unknown instead of number. The reason is that in JavaScript, Number.isFinite happy returns false for non-numbers (whereas isFinite coerces first).
> Number.isFinite(false)
false
> isFinite(false)
true
> Number.isFinite(Symbol(2))
false
> isFinite(Symbol(2))
Uncaught TypeError: Cannot convert a Symbol value to a number at isFinite (<anonymous>)
Now since Number.isFinite is already expected to accept all arguments from any type and return false no matter how wacky the arguments, it makes sense for this behavior to be preserved in TypeScript. Hence the parameter type properly is unknown. For the global isFinite which is intended to work only on numbers (and does the coercion that TypeScript helps us avoid), it makes sense to restrict the parameter to being a number.
But as your question rightly asks, why, given that Number.isFinite will accept any arguments and return true only for numbers, why can't it be a type guard? The reason is that it returns true for some, but not all numbers! Let's try at least to write our own guard:
function numberIsFinite(n: any): n is number {
return Number.isFinite(n)
}
and these make sense:
console.log(numberIsFinite(20)) // true
console.log(numberIsFinite(Number.MAX_VALUE)) // true
console.log(numberIsFinite(undefined)) // false
console.log(numberIsFinite("still ok")) // false
But here is where things go wrong-ish:
console.log(numberIsFinite(Infinity)) // false but uh-oh
console.log(numberIsFinite(NaN)) // false but uh-oh
Now it's true that with this type guard that
const x: number|string = 3
if (numberIsFinite(x)) {
console.log(`A number whose type is ${typeof(x)}`)
} else {
console.log(`A string whose type is ${typeof(x)}`)
}
will print
"A number whose type is number"
so far so good but:
const x: number|string = Infinity
if (numberIsFinite(x)) {
console.log(`A number whose type is ${typeof(x)}`)
} else {
console.log(`A string whose type is ${typeof(x)}`)
}
will print
"A string whose type is number"
And this is silly.
If there was a dependent type in TS called "finite number" then (and perhaps only then) would making Number.isFinite a type guard make sense.
Credit to #VLAZ, whose answer this explanation is based on. I added the second part to my original answer after reading theirs.
Number.isFinite() is not a type guard because it can lead to weird and wrong behaviour in edge cases.
Number.isFinite(4) -> true and the value is a number. That's fine.
Number.isFinite("apple") -> false and the value is not a number. That's fine.
Number.isFinite(Infinity) -> false but the value is not not a number. That's not good.
Some things in JavaScript are of type number but are not finite. These are the values Infinity, -Infinity and NaN. Yes, it stands for "not a number" but it's of type number. It's confusing but makes sense.1
In most cases, we don't care about these non-finite values.
However, as they are still numbers, they are valid in mathematical operations. The concept of infinity is also mathematical and sometimes can be useful.
Discarding these values leads to sometimes wrong code. Let's assume that Number.isFinite() was declared as a type guard. Then consider this code:
function atLeast(minValue: string | number, x: number): boolean {
const min: number = Number.isFinite(x)
? minValue
: Number(minValue.replace(/\D/g, "")); //convert
return num >= min;
}
atLeast(2, 42); //true
atLeast("$3.50", 42); //true
atLeast(-Infinity, 42); //error
This would be valid code. Wrong logic and a bit weird but it's here to just illustrate a point. Still, a more realistic usage might be:
let dynamicMinimum = -Infinity; //allow all
/* ... */
someArray.filter(x => atLeast(dynamicMinimum, x));
The code in the function is accepted by TypeScript and when Number.isFinite() returns false type narrowing would cause minValue would not be considered a number and only allowed to be treated as a string by the compiler.
While the example here is contrived and not too hard to figure out it's wrong, you can easily get into a real world situation where you accidentally narrow a value out of being a number when it's still a number. This would be why Number.isFinite() is not a type guard - it can erroneously assert something about a type that is misleading.
1 Here is what I hope is an intuitive explanation why NaN is a number type. In JavaScript values can be changed and some mathematical operations need a number to work with, otherwise they make no sense. But not everything converts to a number. So when you convert a value to a number, you need to somehow signify that it cannot be converted. This is where NaN comes in.
Since the contextual information for what NaN was before conversion, you cannot definitely say it's equal to anything, hence why NaN == NaN is false. An equivalent code might be Number("apple") == Number("orange") - the two values are clearly not equal before the conversion.
Because there is no way to return a value combined with some guard conditions in typescript. What you can do is
a) Add an additional check for not undefined values (but I think that in your case you probably will not need Number.isFinite anymore)
function inc (n?: number) {
return typeof n === "number" && Number.isFinite(n) ? n + 1 : 1;
}
b) or write your own isFiniteNumber guard.
I have recently read some code that uses !! to convert a variable to boolean for evaluation in an if statement. This seems somewhat redundant to me as the variable would be evaluated for its boolean value anyway. Are there any performance benefits to doing this or is it for better browser support?
Sample Code:
var x = 0;
var atTop = x===window.scrollY;
if(!!atTop){
alert("At the top of the page.");
}
Edit:
I have also seen this for operands that are not of boolean types, but I had always assumed that using if would evaluate the boolean value of the variable anyway as all values in Javascript are either "truthy" or "falsey".
Sample Code:
var x = 1;//or any other value including null, undefined, some string, etc
if(!!x){//x is "truthy"
//wouldn't using if(x) be the same???
console.log("something...");
}
Short answer: No, there is no reason.
In your code, it's already a boolean type, there is no need to convert, and convert it back again: you will always get the same result. Actually, if you have a boolean value (true or false), when you use !! with any of them, it will be converted back to its original value:
console.log(!!true); // Will always be "true"
console.log(typeof !!true); // It's still a "boolean" type
console.log(!!false); // Will always be "false"
console.log(typeof !!false); // It stills a "boolean" type
Answer for edited question: Yes, it's the same. That's what if(...) actually does - it's trying to convert any type to boolean.
Here is a small test, you can play around with that and add whatever you want inside the initialArr array in order to test whether it behaves the same with if and !!:
const initialArr = [
undefined,
null,
true,
false,
0,
3,
-1,
+Infinity,
-Infinity,
Infinity,
'any',
'',
function() { return 1 },
{},
{ prop: 1 },
[],
[0],
[0, 1]
];
function testIsTheSame(arr) {
let equolityCounter = 0;
arr.forEach(item => {
let ifStatement = false;
let doubleNotStatement = !!item;
if (item) {
ifStatement = true;
}
if (
ifStatement === doubleNotStatement &&
typeof ifStatement === typeof doubleNotStatement
) {
equolityCounter++;
}
});
console.log(`Is the same: ${equolityCounter === arr.length}`);
}
testIsTheSame(initialArr);
I would say it was mostly done for code-readability. I doubt there is any significant performance nor compatibility implications (someone feel free to test this please)
But in the code-readability aspect, it would imply to me that this variable previously was not a boolean, but we want to evaluate it as one, if you add new logic concerning this variable, keep that in mind.
Although in your case its already boolean, so its 100% redundant, but I'd guess just a habit of someone for the above reasoning applied excessively, and/or seeing it elsewhere and copying that pattern without fully understanding it (short story time: in C# you can name a protected term a variable name by adding #, so var #class = "hello";, a junior dev just assumed all variable names needed # in front of them, and coded that way. I wonder if someone assumed that an if without a comparison operator needs to have !! in front of it as a comparison operator)
There isn't any run-time benefit (or an objective one) whatsoever to doing this in an if statement. The evaluation performed by the if statement will yield precisely the same result as the evaluation produced by double exclamation mark. There is no difference.
Double exclamation marks is a useful expression to ensure boolean value based on truthyness. Consider, for instance:
var text = undefined;
console.log(text); // undefined
console.log(!!text); // false
// It would make sense here, because a boolean value is expected.
var isTextDefined = !!text;
// It would also affect serialization
JSON.stringify(text); // undefined (non-string)
JSON.stringify(!!text); // "false"
I suppose that this is a habit that was picked up because of the above use cases, thus always converting to boolean when wishing to address a variable's truthyness. It's easier for us (humans and programmers) to follow a rule when it's always applied. You'll either use the blinkers in your car all the time, even when there's nobody around, or it's likely that you'll occasionally (or maybe often) forget to signal when you should have.
It all depends on the value of atTop variable. Follow the discussion here.
In summary, if the value of atTop is anything different to a boolean, the first negation will convert it to a boolean value (negated). Second negation will return the boolean value to the equivalent boolean of the original atTop value.
For example, if atTop is undefined, first ! will turn it to boolean true, then the second ! turns it to boolean false (which would be the equivalent boolean of undefined)
However, in your code the atTop value is the result of an strict equality ===, which means you always get a boolean as a result in atTop. Thus, you don't need to convert a non-boolean value to boolean, and so, the !! is not needed.
I'd like to know whether String.replace() actually found a match and performed a substitution. Since String.replace() returns the resulting string rather than the number of substitutions performed, it seems that I would have to compare the original with the result.
The question is, should I use === or == for that comparison?
As far as I can tell, neither the Mozilla documentation nor the ECMAScript 5.1 Standard specifies that the string that is returned must be the same object as the string that was passed in, if no match occurred.
On the other hand, it would seem stupid for any implementation of JavaScript to return a copy of an unchanged string.
In concrete terms, what happens with
var s = 'abc';
var t = s.replace(/d/, 'D');
console.log(s === t); // I expect true, but am not sure
Is it
Guaranteed to print true? If so, where is that behaviour documented?
Undefined and unreliable behaviour (i.e., I should test s == t instead, or do something clever with a replacement callback closure)?
Undefined behaviour that in practice returns true on every JavaScript implementation?
Edit
#cookiemonster asks:
So it seems that you're not really wondering if the result is guaranteed, but more whether an implementation is optimized to perform an identity comparison internally. Is that right?
Actually, I did screw up the question, and it ended up being an X-Y problem. What I really want to know is, how can I check whether any substitution occurred (the actual number of substitutions doesn't matter — one or more times are all the same)? And do so efficiently, without doing a separate .match() or a character-by-character comparison. And be certain that the result is guaranteed by the language specification.
=== won't work with a String object:
a = new String("foo")
a.replace(/XXX/, "") == a
> true
a.replace(/XXX/, "") === a
> false
or any object that has a custom toString method:
b = { toString: function() { return "foo" }}
"foo".replace(/XXX/, "") == b
> true
"foo".replace(/XXX/, "") === b
> false
Most of the time, this is a non-issue, but "praemonitus, praemunitus" as they say.
To answer your update: as seen here, at least V8 is optimized to return the subject itself if no replacements can be made:
int32_t* current_match = global_cache.FetchNext();
if (current_match == NULL) {
if (global_cache.HasException()) return isolate->heap()->exception();
return *subject; <-------
and, although the standard only requires two strings to look the same to be strict equal (===), I'm absolutely positive that every JS engine out there is smart enough to avoid strcmp on equal pointers.
It makes no difference.
Why? Because String.replace operates on strings, and returns a string. Also, strings are primitives, not objects.
You already know that you have two strings. == and === are therefore identical for this purpose. I'd even go so far as to say that === is superfluous.
The replace method on the String class always returns a string, so === is just as safe to use and reliable as == since no type coercion will happen. Secondly, if no substitution occurred, the === test will return true since they contain the same characters.
Given your example...
"Is it Guaranteed to print true? If so, where is that behaviour documented?"
Yes, it is. It's documented in the respective equality comparison algorithms used by == and ===.
Abstract Equality Comparison Algorithm
Strict Equality Comparison Algorithm
"Is it Undefined and unreliable behaviour (i.e., I should test s == t instead, or do something clever with a replacement callback closure)?"
No, it's well defined behavior. See above. The == and === operators will behave identically.
"Is it Undefined behaviour that in practice returns true on every JavaScript implementation?"
As long an implementation is following the specification, it will return true.
Give the following snippet
function countZeroes(array) {
function counter(total, element) {
return total + (element === 0 ? 1 : 0);
}
return reduce(counter, 0, array);
}
What does the === do?
Is reduce a built in function? What does it do?
Please explain the steps of this program.
It is the strict equality operator.
It compares two values and checks to see if they are identical according to the Strict Equality Comparison Algorithm.
This is opposed to ==, which will attempt to coerce one or both of the values being compared if they are of different types. That one uses the Absract Equality Comparison Algorithm.
The rules for the Abstract algorithm can be tricky. You're better off using === unless you have special need for ==.
From the MDC docs
The standard equality operators (== and !=) compare two operands without regard to their type. The strict equality operators (=== and !==) perform equality comparisons on operands of the same type. Use strict equality operators if the operands must be of a specific type as well as value or if the exact type of the operands is important. Otherwise, use the standard equality operators, which allow you to compare the identity of two operands even if they are not of the same type.
With regard to the code, this part:
(element === 0 ? 1 : 0)
...basically says if the value of element is exactly equal to 0, then use 1, otherwise use 0.
So to take that entire line:
return total + (element === 0 ? 1 : 0);
...the return value of the function will be total + 1 if element equals 0, otherwise the return value will be total + 0.
You could rewrite the code using an if-else statement:
if( element === 0 ) {
return total + 1;
} else {
return total + 0;
}
=== is the same as == except it doesn't cast variables
0 == '0' -> true
0 === '0' -> false
reduce isn't a built in function, but what it certainly does is run counter on each element of the array.
so for each element of the array the element is checked to be 0 and if it is the total is incremented.
=== is the identity operator, it's like ==, but does not perform type conversion.
this function appears to count the number of zeros in an array and return the count.
I assume that reduce() acts like Array.prototype.reduce
=== is strictly equal, both sides have to be of the same type and be equal. This is used to avoid the comparison of 2 unequal types (usually boolean false and a number 0)
The "===" is means "exactly equals", as in the value is the same, as is the type. So ...
var x = 5;
if (x === 5) {
alert("This will happen");
} else {
alert ("This won't");
}
It's rarely used.
The reduce function is likely the Array.prototype.reduce() method, which is used to apply a function to values in an array sequentially (sort-of). So, in this usage it is applying the 'counter' function to everything in the array, which will count the # of zeros in the array and return that.
Its a very good question and generally developer coming from other languages always have difficulty understanding the importance of using === as compare to ==
1. 5 == '5' //true why? Because it do
type conversion whereas in case with
=== 5 === '5'//false because '5' is a string as compare to number 5.
2. '\t\r\n' == 0 //true this lack of transitivity is alarming and cause
lot of errors.
3. Use JsLint ...it will help writing better JS code keep your code safe
from this kind of issues.
4. Moreover their is a performance penalty for using == when you are
comparing number with a string.
In my test it turns out that there is
little practical performance
difference between == and ===. While
the strict operator is marginally
faster (roughly 10%) in most browsers
when combined with explicit type
conversion, such as a === +b, the
only real performance gains will come
from avoiding type conversion
entirely. Converting a string to an
integer for comparison with another
integer is significantly slower (up
to 10x) than simple comparing two
integers. You should never allow
integers to be stored as strings
internally, as the type conversion
will incur a performance penalty.
While that was the basic takeaway from the numbers, I did find one interesting outlier when testing with Firefox. In Firefox, the comparison a === +b is about 20x slower than the equivalent a == b when a is an integer and b is a string integer. This result seems suspicious to me, and nothing similar occurred in any other browser. Oddly, when the Firebug script debugger is turned on, this result changes, and a === +b becomes about 10% faster than the other. I'm not sure what to make of this result, but it does serve as a reminder that integers should always be stored in numbers, not in strings.
see other answer about ===.
reduce it built in JS function which uses like "foreach", its moving on every elemnt in the array.
it start with the inital value, which in your case its zero, and then call to counter() and on the first element.
it check it, and return total(which is zero)+ 1 if the element is 0, after the returned value will be the "total" for the 2nd element in the array and so on....
in conclusion: the reduce call to counter on every element of the array,doing the test and adding its value to the (n-1)st element's returned value;
=== is a strict equality comparison. The == operator in JavaScript does type coercion, which often has surprising results, like how ' ' == false. So most JavaScript developers use === where possible.
Hard to tell about reduce(). That is not a built-in global function in JavaScript, but it likely refers to the reduce() method on JavaScript arrays. The reduce() method executes counter() once for every element in the array, and each time it calls counter(), it replaces total with the returned value from the counter() call. So the given function counts the number of elements that are strictly equal to zero in array.