Determining type conversion programmatically - javascript

I would like to find a way to programmatically (i.e. by writing code) find for what values of x we have the expression x == null evaluating to true.

It is impossible to (without prior knowledge of at least the basic JavaScript rules) be able to programmatically determine all values of x for which x == null is true. However, the following should show a pattern from which a heuristic can be derived:
var v = [null, undefined, false, true, -1, 0, 1, "", " ", "0", {}, []]
for (var i = 0; i < v.length; i++) {
var x = v[i]
alert(x + " == null? " + (x == null))
}
(This particular test case does cover all the times when it would be true.)
Similar tests can be done for == false, etc.
Happy coding.
See Ray Toal's answer for more suggestions of test values.

In the absence of knowing at least something about how JavaScript performs type conversions the way these conversions are applied over the operator == you would have to test every possible value against null, and the number of possible values are unlimited, so what you ask cannot be done.
With a little bit of knowledge you can break down the world of all possible JavaScript expressions into the following categories:
undefined
null
true
false
0
negative finite numbers
positive finite numbers
negative infinity
positive infinity
NaN
empty string
a string full of whitespace
a string with at least one non whitespace character
an empty object
an object with some properties
Test a representative value from each class against null and see what you get.
I assume from the way the question was phrased that you know the exact section in the ECMA-262 specification that defines, precisely, the semantics of ==. ( Section 11.9.3 of the 5.1
spec )

Related

how to understand javascript coercion? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 6 years ago.
Improve this question
I was watching this talk, and on 16:34 there is a javascript coercion test:
5 - "4" // 1
5 + "4" // 54
+!{}[true] // 1
+[1] // 1
+[1, 2] // NaN
7 - "a" // NaN
7 / 0 // Infinity
What is the exact logic behind those calculations?
5 - "4" // 1
The - operator coerces its operands to numbers. See the subtraction operator and the abstract ToNumber operation it uses.
5 + "4" // 54
When either operand is a string, the + is string concatenation, not addition, and the other operand is coerced to string if necessary. See the addition operator and the abstract ToPrimitive and ToString operations.
+!{}[true] // 1
Explaining this is pointless. Don't do that in your code.
Oh, okay:
{}[true] is evaluated first. The true is coerced to "true" (via ToString linked above) because it's used in a property accessor and isn't a Symbol. {} is an empty object, so {}[true] is undefined, leaving us with +!undefined.
!undefined is true, because it coerces undefined to a boolean via the abstract ToBoolean operation, and then negates that to get true.
+true is 1, because of ToNumber linked above.
+[1] // 1
[1] is an array with a 1 in it. Applying + to it runs it through ToPrimitive, which ultimate ends up being [1].join(","), giving us..."1". +"1" is 1 thanks to ToNumber.
+[1, 2] // NaN
Almost exactly like the above, but since the string "1,2" can't be completely parsed as a number, we get NaN.
7 - "a" // NaN
Almost exactly like our first example. ToNumber("a") is NaN, and any calculation involving NaN (such as substraction) results in NaN.
7 / 0 // Infinity
In JavaScript, division by 0 is defined as Infinity; see the Applying the / Operator.
As you can see, these are all understandable, with effort, by referring to the specification. Some are tricky, but really the tricky ones are things you'd almost never run into in the real world.
What is your resource of choice to understand type coercion in javascript?
The spec.
Some examples:
to understand why 5 - "4" === 1, I would look for the binary - operator in the spec and see that ToNumber is called on each argument.
to understand why +!{}[true] === 1, I would first understand that {}[true] uses the bracket notation property accessor, which uses ToPropertyKey on the value, which will use ToString on true since true is not a Symbol, so it is the same as {}["true"], and since that object has no property called "true" the result is undefined, then to understand why +!undefined === 1 I would look at the spec for the unary logical ! operator and see that it uses ToBoolean (before negating the result), and ToBoolean converts undefined to false. To understand why +true === 1, I would look at the spec for the unary + operator and see that it calls ToNumber on its operand, and ToNumber evaluates true to 1.
The rules are actually pretty straightforward and intuitive once you are accustomed to them, which happens pretty quickly. If you learn them from the spec, there are no surprises.
To understand coercion you simply need to understand what is going on. Firstly, JavaScript is a dynamically typed language. Unlike some other programming languages, JavaScript doesn't require you to define a variable's type.
Example:
var a = 1
//you are not telling JavaScript that
// 1 is an integer, you are just defining it as is
So prior to attempting to breakdown the examples you have listed, you must next understand that to apply a method to an object, both methods have to be the same type.
Example:
5 + "hello" = ?
// in math, you can't possibly add a number to a word right?
// and JavaScript realises that.
// But instead of throwing an error, it "coerces" the
// integer 5, into a string "5",
// giving you the answer "5hello"
Lastly I would use the first 2 examples as a contrast for coercion.
The first one states 5 - "4" = 1 while the second one is 5 + "4" = "54".
The main reason for difference in result is largely because of the symbol involved. While we can "add" strings together (simply joining them) but how exactly should we be "minusing" strings?
While this may be a very brief explanation of coercion in JavaScript but hopefully it gives you a clearer picture.
to understand the logic between symbold that have functions:
1.) 5 (integer type) minus 4 (string type) results 1, 4 implemented as int
2.) 5 (integer type) plus 4 (string type) results 54, 5 implemented as string
3.)+plus !is not {} brackets results true
4.)plus array one+[1], results 1
5.)plus array one and two(multiple data set), results Nan, not do-able
6.)7 (int) minus string("a"), results Nan since its not possible
7.)7 divide by 0 , results in infinity like in math functions if a number is divided by 0 is always infinite
Wiki:Coercion /koʊˈɜːrʃən/ is the practice of forcing another party to act in an involuntary manner by use of intimidation or threats or some other form of pressure or force.
like number 1 is int against string which does not fit and forcefully written
It's just to help you understand the logic behind the language.Hope this helps :)

So I can't put Infinity into JSON as a number, can I? [duplicate]

This question already has answers here:
JSON left out Infinity and NaN; JSON status in ECMAScript?
(10 answers)
JSON.stringify converting Infinity to null
(3 answers)
Closed 8 years ago.
I managed to find a bug (maybe not bug, but huge pain in the ass) that took an impossibly long time to track down, and can replicate it using the REPL (NodeJS):
> o = {};
{}
> JSON.stringify(o)
'{}'
> o.n = 10
10
> JSON.stringify(o)
'{"n":10}'
> o.n = Infinity;
Infinity
> JSON.stringify(o)
'{"n":null}'
> null == Infinity
false
> null === Infinity
false
> typeof 10
'number'
> typeof Infinity
'number'
When you put Infinity into JSON it becomes null, despite Infinity being a number type. Normally who cares, but when -Infinity, NaN, 0, and Infinity all have special meaning in the context of your application (machine learning), it's pretty important to be able to transmit special numbers as plain JSON without resorting to stuffing and unstuffing it into a string every time.
String stuffing requires an extra type check for every access, then a switch case string comparison against all special number types, followed by a reallocation to the actual special number type. Once isn't bad, 40 or 50 trillion times a minute is where you really start to curse the ECMA gods.
Am I missing something, or is this just one of those things ECMA considered not so important?
Apprently it was intentional:
http://www.ecma-international.org/publications/standards/Ecma-404.htm
JSON is agnostic about numbers. In any programming language, there can
be a variety of number types of various capacities and complements,
fixed or floating, binary or decimal. That can make interchange
between different programming languages difficult. JSON instead
offers only the representation of numbers that humans use: a sequence
of digits. All programming languages know how to make sense of digit
sequences even if they disagree on internal representations. That is
enough to allow interchange.
You can't use NaN and Infinity in classic JSON, unfortunately, JSON is very limited. It has nothing to do with ECMA, JSON wasn't created by them and frankly speaking it has little in common with JavaScript.
If you want to use all javascript numbers, I suggest to serialize your data using JSON5 instead.
That's correct, JSON cannot represent all JavaScript values:
(quoted from JavaScript Definitive Guide, 6th editon, O'Reilly, p.138):
JSON syntax is a subset of JavaScript syntax, and it cannot represent
all JavaScript values. Objects, arrays, strings, finite numbers, true,
false, and null are supported and can be serialized and restored. NaN,
Infinity, and -Infinity are serialized to null. Date objects are
serialized to ISO-formatted date strings (see the Date.toJSON()
function), but JSON.parse() leaves these in string form and does not
restore the original Date object. Function, RegExp, and Error objects
and the undefined value cannot be serialized or restored.
So, we have already established that -Infinity, Infinity, and NaN are not legal JSON values. Here is my proposal for how to handle this effciently.
'n' can continue to hold either a legal JSON value, or null (for an illegal value). But, if the value is illegal, you can have a special property (that only needs to exist if 'n' is null) -- call it "altValue" -- whose possible values can be "-Infinity", "Infinity", and "NaN". You can also have an object that maps each of these string values to the corresponding Javascript value.
When accessing the "n" value, you'd need to do a null check (and presumably that will suffice in most cases). In the rare cases where 'n' is null, you just need to map the "altValue" value to the corresponding Javascript value.
For example:
var altValueMap = {
"-Infinity": -Infinity,
"Infinity": Infinity,
"NaN": NaN
}
function MyData(n){
this.n = n;
if (!isFinite(n)) {
this.altValue = (n === Infinity) ? 'Infinity' : (n === -Infinity) ? '-Infinity' : 'NaN';
}
}
function getN(data) {
return (data.n === null) ? altValueMap[data.altValue] : data.n;
}
var x = new MyData(NaN);
var y = JSON.stringify(x);
var z = JSON.parse(y);
getN(z); // Returns NaN

Why eval("475957E-8905") == "475957E-8905" is true?

I made a program with nodeJs which generate code such as
eval("XXXXXX") == "XXXXXX"
It's working pretty well, but at a moment he gave me this :
eval("475957E-8905") == "475957E-8905"
I tested it with Firebug, and the result is true
.But I don't really understand why.
Of course, eval("475957E-8905") return 0
but why 0 == "475957E-8905" ?
There are two pieces to this puzzle: floating-point numbers and type-insensitive comparison using ==.
First, 475957E-8905 evaluates as the floating point number 475957 * 10 ^ -8905, which is incredibly small; in floating-point terms, it's the same as 0 due to the precision limitations of javascript. So, eval("475957E-8905") returns 0.
Now, for the second piece of the puzzle.
The == means that the types don't have to match, so nodejs (like any JavaScript engine) tries to convert one of them so it can compare them.
Since eval("475957E-8905") returned 0, it tries to convert "475957E-8905" to an integer as well. As we have seen, that is also 0. Thus, the comparison is 0 == 0, which is true.
Note that the same thing happens if you do eval("3") == "3" or eval("3") == 3 -- in each case, the strings are converted to numbers and compared.
Avoiding this problem
You can force a type-sensitive comparison like this:
eval("475957E-8905") === "475957E-8905"
which returns false, because the === tells the javascript engine to return true only if the types and the values both match.
Javascript has to convert your string, "475957E-8905", to a number in order to compare them. When it does that, it converts "475957E-8905" to 0 as well. So, 0 == 0;
As you can see:
"475957E-8905" == 0
Is true. Basically you eval statement "475957E-8905" into a number, and then the other "475957E-8905" is being converted to a number for comparison. In the end, the exact same conversion process has happened to both of them and they are both 0.
use === to compare the type as well, for further information:
JavaScript has both strict and
type-converting equality comparison.
For strict equality the objects being
compared must have the same type and:
Two strings are strictly equal when they have the same sequence of
characters, same length, and same
characters in corresponding positions.
Two numbers are strictly equal when they are numerically equal (have
the same number value). NaN is not
equal to anything, including NaN.
Positive and negative zeros are equal
to one another.
Two Boolean operands are strictly equal if both are true or
both are false.
Two objects are strictly equal if they refer to the same Object.
Null and Undefined types are == (but not ===). [I.e. Null==Undefined (but not Null===Undefined)]
check this documentation

Fastest way to check if a JS variable starts with a number

I am using an object as a hash table and I have stuffed both regular properties and integers as keys into it.
I am now interested in counting the number of keys in this object which are numbers, though obviously a for (x in obj) { if (typeof x === "number") { ... } } will not produce the result I want because all keys are strings.
Therefore I determined that it is sufficient for my purposes to assume that if a key's first character is a number then it must be a number so I am not concerned if key "3a" is "wrongly" determined to be a number.
Given this relaxation I think i can just check it like this
for (x in obj) {
var charCode = x.charCodeAt(0);
if (charCode < 58 && charCode > 47) { // ascii digits check
...
}
}
thereby avoiding a regex and parseInt and such.
Will this work? charCodeAt is JS 1.2 so this should be bullet-proof, yes?
Hint: I would love to see a jsperf comparing my function with what everyone comes up with. :) I'd do it myself but jsperf confuses me
Update: Thanks for starting up the JSPerf, it confirms my hope that the charCodeAt function would be executing a very quick piece of code reading out the int value of a character. The other approaches involve parsing.
parseInt(x, 10) will correctly parse a leading positive or negative number from a string, so try this:
function startsWithNumber(x) {
return !isNaN(parseInt(x, 10));
}
startsWithNumber('123abc'); // true
startsWithNumber('-123abc'); // true
startsWithNumber('123'); // true
startsWithNumber('-123'); // true
startsWithNumber(123); // true
startsWithNumber(-123); // true
startsWithNumber('abc'); // false
startsWithNumber('-abc'); // false
startsWithNumber('abc123'); // false
startsWithNumber('-abc123'); // false
Why speculate when you can measure. On Chrome, your method appears to be the fastest. The proposed alternatives all come at about 60% behind on my test runs.
The question is misleading because it is hard to tell this of a variable's name but in the example you're dealing with object properties (which are some kind of variables of course...). In this case, if you only need to know if it starts with a number, probably the best choice is parseInt. It will return NaN for any string that doesn't start with a number.
You could also use isNaN(x) or isFinite(x) - see this SO question

Javascript equality triple equals but what about greater than and less than?

I was explaining to a colleague that you should use === and !== (and >== and <== of course) when comparing variables in JavaScript so that it doesn't coerce the arguments and get all froopy and confusing but they asked me a two part question that I did not know the answer to and thought I would ask the experts here, specifically it is:
What about > and < - when they compare do they also coerce the arguments or not - why isn't there some sort of >> and << operator (probably need to be some other syntax as I would guess they would be bit shift operators if it is going along the whole C style but you get the gist)?
So I can write a test to find the answer to the first part, which I did, here it is:
// Demo the difference between == and ===
alert(5 == "5");
alert(5 === "5");
// Check out what happens with >
alert(5 > "4");
alert(5 > 4);
and it returned:
true
false
true
true
so it does look like the > is doing the coercion since > "4" and > 4 return the same result. so how about the second part...
Is there some sort of operator for > and < that do not coerce the type (or how can I change my test to perform the test safely)?
No, there's no need for such operators. The type checking done for those relational operators is different than for equality and inequality. (edit — perhaps it's a little strong to say that there's "no need"; that's true only because JavaScript deems it so :-)
Specifically, the > and < and >= and <= operators all operate either on two numeric values, or two strings, preferring numeric values. That is, if one value is a number, then the other is treated as a number. If a non-number can't be cleanly converted to a number (that is, if it ends up as NaN), then the result of the comparison is undefined. (That's a little problematic, because undefined will look like false in the context of an if statement.)
If both values are strings, then a collating-order string comparison is performed instead.
If you think about it, these comparisons don't make any sense for object instances; what does it mean for an object to be "greater than" another? I suppose, perhaps, that this means that if you're finding yourself with values of variant types being compared like this, and that's causing problems, then yes you have to detect the situation yourself. It seems to me that it would be good to work upstream and think about whether there's something fishy about the code that's leading to such a situation.
Is there some sort of operator for > and < that do not coerce the type
No.
how can I change my test to perform the test safely
You would have to explicitly test the types:
typeof a === typeof b && a > b
I referenced Flanagan's JavaScript: The Definitive Guide (5th Ed.) and there does not seem to be non-coercive comparison operators.
You are right in saying the << and >> are indeed bitwise operators so that wouldn't work.
I would suggest you deliberately coerce the values youself:
var num_as_string = '4';
var num = +num_as_string;
if (5 > num) { ... }
12 > '100' // false
'12' > 100 // false
'12' > '100' // true
As others mentioned, if one is a number the other is casted to a number. Same rule applies to these cases as well:
null > 0 // false
null < 0 // false
null >= 0 // true
However, there might be cases that you would need null >= 0 to give false (or any of the number string comparison cases above), therefore it is indeed a need to have strict comparison >== or <==.
For example, I am writing a compareFunction for the Array.prototype.sort() and an expression like x>=0 would treat null values like 0's and put them together, whereas I want to put them elsewhere. I have to write extra logic for those cases.
Javascript says deal with it on your own (in practice).

Categories

Resources