I have the following script
document.write("12" < "2");
which returns true. Any reason why? The documentation says that javascript compares strings numerically but, I don't see how "12" is less than "2".
JavaScript compares strings character by character until one of the characters is different.
1 is less than 2 so it stops comparing after the first character.
I believe it is doing a lexicographic comparison - the first char in string one is '1', which is less than the first char of string two, which is '2'. More about Lexicographic order here: http://en.wikipedia.org/wiki/Lexicographical_order
This is because the first character of "12" is 1, which comes before "2"; and JavaScript string comparison is lexically/alphabetically, rather than numerically. Though it appears partially numeric, since 1 is sorted ahead of 2.
You can, however, simply compare the numbers as numbers:
document.write(parseFloat("12") < parseFloat("2"));
Try:
document.write(parseInt("12") < parseInt("2"));
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.
This question already has answers here:
Why is one string greater than the other when comparing strings in JavaScript?
(5 answers)
Closed 6 years ago.
I took a JS course on a website , and in one of the lessons there was a piece Of code that did not make sense to me :
the code is in the picture , why str1 is less then str2 ?
Strings are compared based on standard lexicographical ordering, using Unicode values. That means "a" < "b" and "c" > "b"
Two strings are strictly equal when they have the same sequence of
characters, same length, and same characters in corresponding
positions. source
var str1 = "aardvark";
var str2="beluga";
console.log(str1 < str2);//true
console.log(str1.length < str2.length);//false
This compares each character from 0-index, for example "a"<"b" thi is true. If there are equal, it compares next index, and next, ...
"aad">"aac", because, twice "a"="a" and then "d">"c"
JavaScript in this case will compare the strings lexographically character by character, where the letter 'a' is lower than the letter 'b' and so on. It works for numbers too, and the uppercase alphabet is considerd higher than the lowercase alphabet.
So, in your example, 'a' < 'b' and therefore the statement is true.
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.
var a = ['a100', 'a1', 'a10'];
a.sort();
This logs: ["a1", "a10", "a100"]
var a = ['f_a100_', 'f_a1_', 'f_a10_'];
a.sort();
But this logs: ["f_a100_", "f_a10_", "f_a1_"]
Can you please advise me why is that?
Array.sort sorts value by converting the item to string and then doing a lexicographical sort.
Now, by lexicographical sorting all that they mean is that they compare the string characters one by one till a non matching character is found. The position of the non matching character in the character-set (where letters are ordered alphabetically) decides the rank of the string.
f_a100_
^
f_a1_
^
f_a10_
^
See the first non matching character. Here _ is greater than 0 (check their ascii codes) so f_a100_ and f_a10_ comes above f_a1_. Now between those two we go to the next character
f_a100_
^
f_a10_
^
Here, applying the same logic f_a100_ comes first. So the final order is ["f_a100_", "f_a10_", "f_a1_"]
This sorting order would seem logical for simple strings. But for certain other cases like yours it works weirdly because of the way the charsets are arranged. To get a desired behaviour you should write your own compare function that strips out the number part and return a positive, negative or 0 value as shown in the example.
Javascript sorting is string based:
var a = ['a100', 'a1', 'a10'];
a.sort();
Will return:
["a1", "a10", "a100"]
Because of string comparison: "a1" < "a10" < "a100". In the other example, "f_a100_" < "f_a10_" because "0" < "_", and "f_a10_" < "f_a1_" for the same reason.
Indeed this:
[15, 13, 8].sort();
will return:
[13, 15, 8]
This is something a little weird, but that's how it's designed. If you want to change the ordering criteria you can pass a function as a parameter. E.g. (From here)
var points = [40,100,1,5,25,10];
points.sort(function(a,b){return a-b});
The javascript sort function does sorting alphanumerically not arithmetically so you get the results such. See this question that is almost same with yours Array Sort in JS
In the first case "a1" < "a10" because when comparing two strings the "a1" portion matches but then it decides that "a1" has a shorter length.
But in the second case "f_a1_" > "f_a10_", because when comparing these two the "f_a1" portion matches and then "_" is compared to "0". And '_' > '0' because they are compared by their ascii value.
Array.sort uses string sorting (even if the array is a list of numbers).
The sorting you're looking for is known as natural order sorting. In this sorting numbers are treated as numbers, 100 comes after 10, 2 comes before 10 etc.
JavaScript does not natively have a natsrt. I have written my own implementation but it's quite involved. Here is a reference implementation: http://phpjs.org/functions/strnatcmp/
If you just need to sort strings of the form f_a[0-9]+_ you can write a regular expression to extract the number part.
var i = ['5000','35000'];
alert((i[0] < i[1])?'well duh!':'fuzzy math?');
alert((Number(i[0]) < Number(i[1]))?'well duh!':'fuzzy math?');
What's happening here? In the first alert, the text string "5000" evaluates as not less than "35000". I assumed Javascript used Number() when numerically comparing strings, but apparently that's not the case. Just curious how exactly Javascript handles numerically comparing the strings of numbers by default.
Javascript compares strings by character value, whether the strings look like numbers or not.
You can see this in the spec, section 11.8.5, point 4.
'a' < 'b' and 'ab' < 'ac are both true.