Page 2 of 2
The answer is in the nature of the value passed and in the way that the exact comparison === operator works.
When the rest of the program was examined the following was found:
A user of the utility function had been super object-oriented and created a String object set to "yes" and passed it into the function. Unfortunately === tests for identity and when two objects are concerned identity is rather stronger than just having the same data stored.
Two variables are only identical if they reference the same object and hence s2==="yes" is is clearly false as s2 references one string object and "yes" is a completely different string object hence the comparison is false.
To see that this is the case try:
You will see true for the first call to answer and false for the second. To explore this a little further try:
The result is that false is displayed because s2 and s3 reference different objects, even though they seem to have the same value. To get an example of identity you have to write:
which does display true.
What is perhaps more surprising is that if you try:
If you think all of this is obvious try and predict the outcome of:
The first is false the second is true. In fact, you can use any method that returns a string in place of toString.
gives the same result, i.e. false, true. The reason is that all string methods return a primitive value type, not a string object.
Despite what many tutorials say, a string literal is a different data type to a string object. Whenever you make use of a string literal as if it was a string object it is automatically converted to a string object before its use. So you can use a string literal as if it was a string object - but it isn't.
Perhaps the final confusion is that if you create a string object using the constructor function without new you get a primitive string value type, i.e. a string literal. That is:
displays true and true because s2=String("yes"); is exactly the same as s2="yes". So not using the new operator makes a big difference.
Hence when you compare a string literal to a string object using the identity operator === the result is always false as they are not the same object.
However if you compare a string object to an apparently equal string literal you get false if you use === and true if you use ==. The first result is because they are different objects, the second is because the string literal determines the type used for the test for equality and in this case the string object is automatically converted to a string literal.
Finally, using the String function without new gives you a string literal, but with a new operator you get a string object.
Who would have thought that comparing two strings could be so tricky?
It's difficult to give a simple avoiding pattern for this problem. In its complete generality comparing strings is tricky.
- If you can rely on the fact that one of the comparisons will be a string literal then the equality operator is the safest option as
gives the same answer irrespective of whether or not x is string object or literal.
So this is one example where == is to be preferred over ===.
- If you can't guarantee that one of the items will be a string literal then the problem is much more difficult and the best you can do is:
which gives the same result if x and y are string objects or literals.
However, there is the small problem of what happens if x and y are more general objects, i.e. not string objects.
Equality for value types is relatively easy to define 1==1 obviously, but equality for weakly typed objects is more difficult what does MyObject==YourObject mean?
On the other hand identity for objects is always easy to define - do variables reference the same object? Mix this with the automatic conversion of value types to objects and you have a potential problem.