I understand that using the "===" compares type, so running the following code results in "not equal" because it's comparing a number type to a string type.
var a = 20;
var b = "20";
if (a === b) {
alert("They are equal");
} else {
alert("They are not equal");
}
But I dont understand how using the "==" to compare only the value results in the "They are equal" message.
var a = 20;
var b = "20";
if (a == b) {
alert("They are equal");
} else {
alert("They are not equal");
}
How are the values equal? Isn't the string "20" stored as the ASCII characters 50 and 48 (0110010 and 0110000 in binary) and 20 stored as the actual binary number 0010100?
EDIT: Thanks everyone! I think all the responses are great and have helped me understand this much better.
The == operator compares only the values of the variables. If the types are different, a conversion is operated. So the number 20 is converted to the string "20" and the result is compared.
The === operator compares not only the values, but also the types, so no cast is operated. In this case "20" !== 20
The JavaScript engine sees the a as a number and casts the b to number before the valuation.
When type conversion is needed, JavaScript converts String, Number, Boolean, or Object operands as follows.
When comparing a number and a string, the string is converted to a number value. JavaScript attempts to convert the string numeric literal to a Number type value. First, a mathematical value is derived from the string numeric literal. Next, this value is rounded to nearest Number type value.
If one of the operands is Boolean, the Boolean operand is converted to 1 if it is true and +0 if it is false.
If an object is compared with a number or string, JavaScript attempts to return the default value for the object. Operators attempt to convert the object to a primitive value, a String or Number value, using the valueOf and toString methods of the objects. If this attempt to convert the object fails, a runtime error is generated.
The problem with the == comparison is that JavaScript version 1.2 doesn't perform type conversion, whereas versions 1.1 and 1.3 onwards do.
The === comparison has been available since version 1.3, and is the best way to check of two variables match.
If you need your code to be compatible with version 1.1, 1.2 and 1.3 versions of JavaScript code, you should ensure that the variables all match as if it was an === comparison that was being performed.
Part of the definition of "==" is that the values will be converted to the same types before comparison, when possible. This is true of many loosely typed languages.
Javascript is designed such that a string containing numbers is considered "equal" to that number. The reason for that is simplicity of use for the case of users entering a number into an input field and the site validates it in JS -- you don't have to cast the entered string to a number before comparing.
It simplifies a common use case, and the === operator still allows you to compare with the type considered as well.
As far as I know JavaScript does automatic data type conversion on the fly - so maybe the variables are casted to equivalent types automatically.
Related
I got these 2 examples below -
console.log("a" > "3") // outputs true
console.log("hello" > "3") // outputs true
According to MDN, If both values are strings, they are compared as strings, based on the values of the Unicode code points they contain.
But then they also wrote the following in the next paragraph, Strings are converted based on the values they contain, and are converted as NaN if they do not contain numeric values.
Following this logic, shouldn't both statements be false since no matter what the operator it is, "a" and "hello" are words in strings and they don't have a numerical value, therefore, it should return NaN, and NaN is false; hence, as soon as one of the operands is false, it outputs false?
If I need to adhere to the former statement above, could you please walk me through this logic?
Thanks.
The key phrase from the MDN article is
If both values are strings, […].
Otherwise JavaScript attempts to convert non-numeric types to numeric values
So no, "a", "3" and "hello" are all strings, and when comparing them, they get compared as strings. No conversion to anything occurs.
You are comparing two strings (in quotation marks), not a string to a number. This should answer your question:
"a" > "3" //true
"a" > 3 //false
As you've written,
If both values are strings, they are compared as strings, based on the
values of the Unicode code points they contain
So, on both examples, both values are strings. If you change "3" to 3, the result is:
console.log("a" > 3)
// expected output: false
console.log("hello" > 3)
// expected output: false
That's because, first it's converted as NaN, and then:
If either value is NaN, the operator returns false.
The docs:
If both values are strings, they are compared as strings, based on the values of the Unicode code points they contain.
Otherwise JavaScript attempts to convert non-numeric types to numeric values: ....
Reading the docs, I understand that, if BOTH strings have numerical values (both not NaN), then both are treated as Unicode code points. Otherwise, if BOTH have numerical values, then they're converted.
But anyways, my sugestion for a js beginer: do not get too attached to how the language works for now, and even tho it can compare strings with "greater" and "less than", I dont think there would (or should) be a real life scenario where you would need it.
Also, just for fun, check this pen I made when I first started with js (I was also very confused about comparison and typing xD):
"" == null // this one is fun
Later, after learning more about the language, you'll get why somethings work like they do in js, I also recomending understanding the history of js and the web, it explains a lot of the weird behaviours of the language.
let arr = [1,2,3];
let empArr =[];
for(var i =0; i< arr.length;i++){
console.log('First',typeof empArr);
empArr+=arr[i];
console.log('Second',typeof empArr)
}
The above code gives this output
First object
Second string
First string
Second string
First string
Second string
Could anyone explain how in first iteration type was Array Object then after that it became string.How Javascript Engine works here?
If we run typeof empArr, we will see empArr an object. No matter if we declare it as an array, internally, it is an object. Further, typeof arr[i] shows arr[i] is a number. Therefore, empArr+=arr[i] means we are trying to add an object and a number. Since we are trying to add two different types, it can happen with the help of coercion, implicitly. Coercion means, converting a value of one type to another. JavaScript performs implicit coercion as per the following rules:
operand + operand = result
If at least one operand is an object, it is converted to a primitive
value (string, number or boolean);
After conversion, if at least one operand is string type, the second operand is converted to and the concatenation is executed;
In other case both operands converted to numbers and arithmetic addition is executed.
Note that the primitive value of an array or object is a string.
In our case, empArr is of type object and by rule 1, it is coerced as a string. Now by rule 2, the arr[i] which is a number, is coerced to a string as well and get assigned to empArr.
For more details:
JavaScript addition operator in details
JavaScript type coercion
According to javascript,
typeof [] is "object" ,i.e., every array is actually an object.
if you append anything to a string it will become a string
"1"+1 will equal "11"
It's because of auto type conversion.
The += is a not an array operator, and as the second operand is string - the 1st is converted to string.
Use empArr.push(arr[i])
EDIT: I will rephrase my question, I type Number < String and it returns true, also works when I do typeof(2) < typeof("2").
Number < String => true
typeof(2) < typeof("2") => true
I'm guessing it is the value of ASCII characters of each letter in Number and String but I am not sure if that is the reason this is returning true, and I want to know why does this happens, what processes or how does the interpreter gets to this result?
First answer:
The charCodeAt() method returns the numeric Unicode value of the character at the given index. Read here
Now if you do not specify any index position then character at 0th index is considered. Now, S ASCII value is 83 and N ASCII value is 78. so, you are getting those number. Check here.
And 78 < 83 => true is obvious.
Try "String".charCodeAt(1) and you will get 116 which is ASCII value of t
Second answer based on OP's edited question:
Frankly speaking your comparison Number < String is "technically" incorrect because Less-than Operator < or any similar operator is for expressions, and Number and String are functions and not expressions. However #Pointy explained on how Number < String worked and gave you results.
More insight on comparison operators
Comparison operators like < works on expressions, read here. Typically, you should have a valid expression or resolved value for RHS and LHS.
Now this is the definition of expression, read more here - "An expression is any valid unit of code that resolves to a value. Conceptually, there are two types of expressions: those that assign a value to a variable and those that simply have a value."
So, (x = 7) < (x = 2) or new Number() < new String() is a "technically" valid/good comparison, even this Object.toString < Number.toString() but really not Object < Function.
Below are rules/features for comparisons, read more here
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 distinct objects are never equal for either strict or abstract comparisons.
An expression comparing Objects is only true if the operands reference the same Object.
Null and Undefined Types are strictly equal to themselves and abstractly equal to each other.
The result of
Number < String
is not the result of comparing the strings "Number" and "String", or not exactly that. It's the result of comparing the strings returned from Number.toString() and String.toString(). Those strings will (in all the runtimes I know of) have more stuff in them than just the strings "Number" and "String", but those two substrings will be the first place that they're different.
You can see what those actual strings are by typing
Number.toString()
in your browser console.
JavaScript does the following thing:
"String".charCodeAt(); => 83
"S".charCodeAt(); => 83
"String".charCodeAt(0); => 83
The method charCodeAt(a) gets the char code from position a. The default value is 0
If you compare N > S you will get 78 > 83 => true
For the complete String Javascript calculates the sum of all ASCII char codes.
So I can answer your question with yes.
In JavaScript, variables are loosely typed, so the number 5 and the string "5" may both be treated as a number by several operators. However, is there a generic way to find out JavaScripts conversion abilites in at tunrime, or is it just the overloading of operators for several types that make the loose typing possible?
For example, given a variable a and a string containing a type name type_canditate, is there any way to ask JavaScript, if a may convert to type_candidate in a feasable manner, in contrast to the hard typing operators like instanceof? For example, "5" instanceof Number evaluates false, while Math.sin("5") is perfectly feasable. For numbers, one can obviuosly check if parseFloat(some_number) evaluates to NaN, but this is a special case for numbers.
So, is there any generic way of naming types, and check if some variable may convert to a given type in a useful manner?
There are three primitive data types in JavaScript: string, number and boolean.
Anything can be converted to a string or boolean:
All objects convert to true (except null, which becomes false - I only mention it here because typeof null gives object)
All objects have a built-in toString method which is called when converting to a string.
Converting a number to a string is done by giving the string representation of the number (ie. 5 becomes "5")
Numbers convert to boolean true, unless it's 0 which becomes false.
Converting to a number is a little trickier, but technically possible. If it can find a valid number, then it becomes that number. Otherwise, it becomes NaN.
So basically... any type can become any other type through casting in this way. The only time you have anything resembling an "error condition" is NaN.
I was perusing the underscore.js library and I found something I haven't come across before:
if (obj.length === +obj.length) { ... }
What is that + operator doing there? For context, here is a direct link to that part of the file.
The unary + operator can be used to convert a value to a number in JavaScript. Underscore appears to be testing that the .length property is a number, otherwise it won't be equal to itself-converted-to-a-number.
According to MDN:
The unary plus operator precedes its operand and evaluates to its
operand but attempts to converts it into a number, if it isn't
already. For example, y = +x takes the value of x and assigns that to
y; that is, if x were 3, y would get the value 3 and x would retain
the value 3; but if x were the string "3", y would also get the value
3. Although unary negation (-) also can convert non-numbers, unary plus is the fastest and preferred way of converting something into a
number, because it does not perform any other operations on the
number. It can convert string representations of integers and floats,
as well as the non-string values true, false, and null. Integers in
both decimal and hexadecimal ("0x"-prefixed) formats are supported.
Negative numbers are supported (though not for hex). If it cannot
parse a particular value, it will evaluate to NaN.
It's a way of ensuring that obj.length is a number rather than a potential string. The reason for this is that the === will fail if the length (for whatever reason) is a string variable, e.g. "3".
It's a nice hack to check whether obj.length is of the type number or not. You see, the + operator can be used for string coercion. For example:
alert(+ "3" + 7); // alerts 10
This is possible because the + operator coerces the string "3" to the number 3. Hence the result is 10 and not "37".
In addition, JavaScript has two types of equality and inequality operators:
Strict equality and inequality (e.g. 3 === "3" expresses false).
Normal equality and inequality (e.g. 3 == "3" expresses true).
Strict equality and inequality doesn't coerce the value. Hence the number 3 is not equal to the string "3". Normal equality and inequality does coerce the value. Hence the number 3 is equal to the string "3".
Now, the above code simply coerces obj.length to a number using the + operator, and strictly checks whether the value before and after the coercion are the same (i.e. obj.length of the type number). It's logically equivalent to the following code (only more succinct):
if (typeof obj.length === "number") {
// code
}