We suppose that we have 3 variables : a,b and c
var a = new Boolean(true);
var b = true;
var c = new Boolean(true);
console.log("First comparison : ", a == b);
// true
console.log("Second comparison : ", b == c);
// true
console.log("Contradiction : ", a == c);
// false
I already know that the keyword 'new' creates a new object.
The type of this object, is simply object.
Mathematically, how can we explain this contradiction ?
In the first two examples, since the comparison involves a primitive value of b, a and c end up being coerced to primitives. In the last case, on the other hand, you are comparing two distinct objects, and therefore no coercion takes place.
To be precise, the double-equal comparison with a boolean uses this rule from the spec (taking the case of b == c):
If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
So this means that ToNumber(b) is compared with c. ToNumber(b) is 1. So we are comparing 1 with c. Next, the following rule is applied:
If Type(x) is either String or Number and Type(y) is Object,
return the result of the comparison x == ToPrimitive(y).
So this means we compare 1 with ToPrimitive(c) which is ToPrimitive(Boolean(true)). ToPrimitive invokes valueOf, which yields 1. So we compare 1 to 1. QED.
In the case of your third example, the following portion of the spec applies:
If Type(x) is the same as Type(y), then...Return true if x and y refer to the same object. Otherwise, return false.
To answer your question:
Mathematically, how can we explain this contradiction ?
It's not a matter of mathematics. It's a matter of the definition of comparisons in the JS spec.
Mathematically, how can we explain this contradiction?
If you think this is a contradiction is probably because you assumed that == defines an equivalence relation.
But it doesn't:
It doesn't satisfy reflexivity, e.g. NaN != NaN.
It doesn't satisfy transitivity, as you noticed.
It satisfies symmetry, though, but that alone is not enough.
I don't think this kind of behaviour can be explained from a mathematical standpoint.
What you are doing on the variables a and c is commonly referred as "boxing": taking a Javascript primitive value (undefined, null, String, Number, Boolean, Symbol in ES6) and calling it with the newoperator.
The result of:
var a = new Boolean(true);
is a Javascript Objectwrapping a Boolean primitive value.
The same invocation pattern implicitly happens when you use a primitive value as the context (this) in some of the language built-in facilities such as Function.prototype.call and Function.prototype.apply
Even replacing ==with === would yield the same results, and that's because of how the Objects comparison work in JS.
Related
I know the difference between == and === when applied to primitive values. But for objects, they both seem to be a simple identity comparison.
var a = {}
var b = a
var c = {}
a == b // true
a === b // true
a == c // false
a === c // false
Is there any situation where comparing two objects will provide different results for each operator, or are they functionally equivalent?
Yes, comparing two objects with == is the same as comparing them with ===. Just as comparing two strings with == is the same as ===. If the type of values are the same, both comparing methods will give the same result. As the specification states:
7.2.14 Abstract Equality Comparison
The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed
as follows:
If Type(x) is the same as Type(y), then
Return the result of
performing Strict Equality Comparison x === y.
Looks like it
The only way I know to "check for object equality" in javascript is to deep check every possible key (but even then it is just duck type checking)
The extra = in === ensures both sides are of the same type. a and c both are objects, the same type. So == or === is irrelevant here.
Well... === is "compare identity and type". You've determined that you're comparing two objects (so "type" is the same), that leaves "compare identity", which is the same as ==.
Likewise, if you compare two numbers, since you already know they are the same type (number), === is the same as ==. There is nothing special or different about objects vs. primitives here. It's just that the only type for objects is object.
This question already has answers here:
Why is `[] == false` is true but just `[]` evaluates to true? [duplicate]
(4 answers)
Closed 8 years ago.
I'm trying to figure out why JavaScript has this strange behaviour in comparing the same array:
var array = [0];
console.log(array == array); //true
console.log(array == !array); //true?
The first one is easily done, they are referencing the same object, but the second is a really tricky one, and I'm working on understanding the process.
Please note that I'm aware that this is abstract equality comparison and not strict equality comparison, and I know their differences (I know that using === would lead to false result, but I'm trying to figure out the behaviour with ==).
P.s.: this one was taken from wtfjs.com, and I didn't find out the explanation, so I tried to give it myself and thought it could be "useful".
The first equality is simple, it's a comparison between the same object (same reference), so it returns true.
The second one is a bit tricky, so I'll try to explain better below.
TL;DR
For those who are a bit lazy, here is a simple explanation without quoting the spec every step:
[0] == ![0] => we evaluate ![0] first, which yields false(because [0] is a truthy value).
[0] == false => [0] is evaluated to [0].toString() which is "0".
"0" == false => "0" is converted to the number 0; the same is for false, so we obtain:
0 == 0 which is finally true.
Complete explanation
As for the first equality, for the sake of completeness, I quote here the interested part of the spec.
1.f Return true if x and y refer to the same object. Otherwise, return false.
So this returns true, as expected. Now the tricky part:
First of all, we have to evaluate the UnaryExpression on the right:
Let expr be the result of evaluating UnaryExpression.
Let oldValue be ToBoolean (GetValue(expr) ).
If oldValue is true, return false.
Return true.
But ToBoolean uses this algorithm, and GetValue should return either an Object or a non-empty String, so the result of the evaluation is true. Returning to our UnaryExpression, we have !true, so the result of the final evaluation is false.
So we're back at our original comparison, now we are comparing an Object against a Boolean.
7.If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
ToNumber(false) is 0, so now we are comparing Object and Number.
Back to the specs:
9.If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.
Calling ToPrimitive on our array should return its [[DefaultValue]], which should be, according to this kangax's answer, the result of calling toString on the array itself, so we obtain "0".
So, back to our comparison, it has became an equality between a String and a Number.
5.If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
Calling ToNumber on our string "0" yields 0, again we are finally at a simple comparison: 0 == 0.
Final spec step:
1.c.iii If x is the same Number value as y, return true.
And here the result explained.
The algorithm for the == operator evaluates the expressions from left to right, so given:
var array = [0];
and evaluating:
array == !array;
then first the left hand expression is evaluated and an array is returned. Then the right hand expression is evaluated: ToBoolean is applied to array and, since it's an object, it returns true and the ! operator reverses that to false.
Then the abstract equailty comparison algorithm is used. Again, the left hand side is evaluated first. Since array is an Object and not a Boolean, String or Number, step 7 is used and the right hand side is converted to a Number and the comparison becomes:
array == 0;
The algorithm is run again and gets to step 9, where array is converted to a primitive (string in this case) and the comparison becomes:
'0' == 0;
The algorithm is run again and gets to step 5 where the left hand side is converted to a Number and the comparison becomes:
0 == 0;
The algorithm is run again and this time the expressions have the same Type (Number) so step 1.iii.c is used to return true.
Please note that through all of this, the left hand side is always evaluated first, though sometimes that results in the right hand side being modified and not the left (e.g. at step 7 of the algorithm).
The Python use of 'is' seems to be similar to JavaScript '===' but not quite.
Here they talk about exact instances:
http://www.learnpython.org/en/Conditions
here (for JS) they talk about "equal AND the same type."
http://www.w3schools.com/js/js_comparisons.asp
SO can you have two different instances of (say) a string of "Bob" and have them not return true when compared using 'is'? Or is it infact the same as ===?
I am guessing this is related to strict vs non-strict typed languages. . . .
Python Part
SO can you have two different instances of (say) a string of "Bob" and
have them not return true when compared using 'is'? Or is it infact
the same as ===?
a = "Bob"
b = "{}".format("Bob")
print a, b
print a is b, a == b
Output
Bob Bob
False True
Note: In most of the Python implementations, compile time Strings are interned.
Another example,
print 3 is 2+1
print 300 is 200+100
Output
True
False
This is because, small ints (-5 to 256) in Python are cached internally. So, whenever they are used in the programs, the cached integers are used. So, is will return True for them. But if we choose bigger numbers, like in the second example, (300 is 200+100) it is not True, because they are NOT cached.
Conclusion:
is will return True only when the objects being compared are the same object, which means they point to the same location in memory. (It solely depends on the python implementation to cache/intern objects. In that case, is will return True)
Rule of thumb:
NEVER use is operator to check if two objects have the same value.
JavaScript Part
Other part of your question is about === operator. Lets see how that operator works.
Quoting from ECMA 5.1 Specs, The Strict Equality Comparison Algorithm is defined like this
If Type(x) is different from Type(y), return false.
If Type(x) is Undefined, return true.
If Type(x) is Null, return true.
If Type(x) is Number, then
If x is NaN, return false.
If y is NaN, return false.
If x is the same Number value as y, return true.
If x is +0 and y is −0, return true.
If x is −0 and y is +0, return true.
Return false.
If Type(x) is String, then return true if x and y are exactly the
same sequence of characters (same length and same characters in
corresponding positions); otherwise, return false.
If Type(x) is Boolean, return true if x and y are both true or both
false; otherwise, return false.
Return true if x and y refer to the same object. Otherwise, return
false.
Final Conclusion
We can NOT compare Python's is operator and JavaScript's === operator, because Python's is operator does only the last item in the Strict Equality Comparison Algorithm.
7. Return true if x and y refer to the same object. Otherwise, return false.
Completely different.
>>> a = 'foo'
>>> b = 'bar'
>>> a + b is 'foobar'
False
>>> 1000 + 1 is 1001
False
>>> a = "Hello, World!!!"
>>> b = "Hello, World!!!"
>>> a is b
False
However note that:
>>> a = "Bob"
>>> b = "Bob"
>>> a is b
True
In this case it condition was True because the compiler is free to intern string literals, and thus reuse the same object, and it does do that with small strings. However there is no guarantee as to when this happens of if this happens at all and the behaviour changes between versions and implementations.
A realiable False output should be:
>>> a = 'Hello, World!!!!'[:-1]
>>> b = 'Hello, World!!!!'[:-1]
>>> a is b
False
Or anything that actually computes the strings.
Python's is keyword compares references (and so is about identity) while === does a minimal amount of coercion (and is therefore concerned with equality, at least in the case of primitives) so they are different.
As I understand it, things that are concerned with identity are concerned with uniqueness from the runtime's point of view (do these two variables point to the same address in memory) while equality is concerned with the uniqueness of the contents of the variables (are these two variables equivalent, regardless of where they are placed in memory relative to each other).
I know that identical objects are not equal, i.e:
var obj = { name: "Value" };
var obj2 = { name: "Value" };
console.log("obj equals obj2: " + (obj === obj2)); //evaluates to false
Yet primitive types are:
var str = "string1";
var str2 = "string1";
console.log("str equals str2: " + (str === str2)); //evaluates to true
My question is why. Why are objects and primitives treated differently? If an object is nothing but an empty container, with only the attributes you specify to put in the container, why wouldn't the container's identical attributes evaluate to be the same? I looked around for this answer on SO and elsewhere, but didn't find an answer.
Is a JS object treated as something different in the DOM than a primitive type?
Thanks
This seems to really be a question about === so let's look at the Strict Equality Comparison Algorithm, in which point 7 says
Return true if x and y refer to the same object. Otherwise, return false.
So what does it mean to be "the same object"? It means they don't just look like eachother, but are at the same place in memory too. This means that the only time when an Object is === to an Object is when they're the same thing.
var a = {},
b = {}, // identical to `a`
c = a; // same as `a`
a === b; // false
a === c; // true
b === c; // false
When a variable's value is an object, well, it isn't an object: it's a reference to an object. Two variables that contain references to the same object are indeed equal:
var myObj = { hello: "world" };
var a = myObj;
var b = myObj;
if (a == b) alert("YES!!"); // YES!!
When the == operator has object references on both sides, the comparison made is to test whether the objects refer to the same object. When primitive values are involved, the semantics are different: the values are directly compared.
Generally, === operator checks for types, and if they are the same, checks values. Object type contains a reference, so, to be equal, they have to reference the same object and be of the same type. String literal value is not a reference, it is a value, so the === will produce true for string literals, but not for "abc" === new String("abc") because latter is an Object.
More information can be found here: A lot of details can be explored from here: Which equals operator (== vs ===) should be used in JavaScript comparisons?
First off, JavaScript objects aren't part of the DOM. The DOM (Document Object Model) are the HTML elements which make up your page. They cooperate together, but aren't directly linked.
Basically, yes, primitives are a special case. You can kind of think of it as if the value of a primitive is a constant (in a sense).
For example, take the example of the number 5. No matter how many times I declare 5, 5 will always equal 5. Thus, it isn't a stretch to say that {var a holding the value 5} is equivalent to {var b holding the value 5}. This concept is a little fuzzier with strings, but it still holds. A string that is "abc" is always the same as any other variable holding a string that is "abc".
This doesn't apply to objects either.
If you have two variables hold the same object, they are eqivalent.
var a = {};
var b = a;
console.log(a == b); // true
console.log(a === b); // true
However, if we create two objects that look similar:
var a = {};
var b = {};
console.log(a == b); // false
console.log(a === b); // false
This seems a bit weird at first, but think about the inner workings that are going on. Consider that when you pass an object in to a function, if you change that object, it is changed outside of the function to. It's passed by reference.
This means you can think of a pointer (a memory address) being stored in the variables. So, if you imagine that they have memory address in them (like 0x123456 and 0x654321), then it makes a little more sense (0x123456 and 0x654321 are different, so you wouldn't expend them to be equal). They are two separate things taking up their own area in the memory.
Make sense?
You can answer to this question at several levels.
strings
Factually, yes, strings are handled differently from objects as far as strict comparison operator is concerned.
Semantically, that is more convenient than having to resort to strcmp or equivalent mechanisms to compare two strings.
Implementation-wise, the cost is neglectible, so JavaScript can offer you that convenience.
By the way, people telling the strict equality operator checks if both variables point to the same memory location are wrong. In case of strings, === will succeed if the string contents are equal, wherever they might be located in memory.
Objects
Semantically, contrary to primitive types like numbers or strings, it is difficult to offer a consistent set of comparison operators for objects.
You could do an in-depth comparison for equality, but greater/lower operators would make little sense.
The choice of Javascript is rather inconsistent here.
the semantics of equality comparison (be it == or ===) are limited to references
(i.e. == or === will succeed if the references are equal).
Implementation-wise, a deep comparison could be quite costly.
There are also subtelties as how to interpret undefined properties.
At any rate, JavaScript did not choose to implement a deep comparison, so if you want one, you'll have to do it yourself.
And there have been terabytes of code written to try and provide the ideal in-depth object comparison function.
ordered comparison is handled quite differently.
You can define a valueOf method that will return whatever primitive value you want to be used for ordered comparison, e.g
myObject.prototype.valueOf = function(){return this.my_comparison_value; };
If not explicitely defined, valueOf will default to "[object Object]".
So if you don't supply a valueOf method:
< and > operators will always return false (which kind of makes sense).
>= and <= will always return true, regardless of the references being equal or not
(which makes a lot less sense).
Now if you take the pain to define a valueOf, equality comparison will still not use it.
The only way to have a consistent behaviour would be to combine <= and >=, e.g.
if (a >= b && a <= b) { // equality using valueOf
For browser-supplied primitive objects like DOM elements, the behaviour of ordering operators depends on what the browser decided to return as a default value.
I would not recomend using that unless you really know what you're doing.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why does (“foo” === new String(“foo”)) evaluate to false in JavaScript?
Over here I caught the advice that it's best to use non type-coercive string comparison, but in Chrome, I discovered something kind of odd:
var t1 = String("Hello world!");
var t2 = new String("Hello world!");
var b1 = (t1==t2); // true
var b2 = (t1===t2); // false
Is this standard behavior? If so, what are the respective types of t1 and t2? Thanks.
If you don't use the "new" keyword with String, you get a primitive string.
If you use "new" keyword, you get a string object instead of primitive.
When you use == it will try to convert to a comparable type, so it can be equal.
If you use ===, it won't convert, so an object can not equal a primitive.
Here is the explanation
typeof String("Hello world!");
"string"
And:
typeof new String("Hello world!");
"object"
when you use === it is paying attention to the type so it returns false
String, called as a function, converts its argument to a string. String, called as a constructor, creates an object whose prototype is the String function. (Check James's Answer for the relevant ECMAScript specification section.)
This is indeed confusing.
The two equality operators actually do very different things. From the ECMA-262, v 5.1 document, === does:
If Type(x) is different from Type(y), return false.
If Type(x) is Undefined, return true.
If Type(x) is Null, return true.
If Type(x) is Number, then
a. If x is NaN, return false.
b. If y is NaN, return false.
c. If x is the same Number value as y, return true.
d. If x is +0 and y is -0, return true.
e. If x is -0 and y is +0, return true.
f. Return false.
If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise, return false.
If Type(x) is Boolean, return true if x and y are both true or both false; otherwise, return false.
Return true if x and y refer to the same object. Otherwise, return false.
Whereas == does:
If Type(x) is the same as Type(y), then
a. If Type(x) is Undefined, return true.
b. If Type(x) is Null, return true.
c. If Type(x) is Number, then
i. If x is NaN, return false.
ii. If y is NaN, return false.
iii. If x is the same Number value as y, return true.
iv. If x is +0 and y is -0, return true.
v. If x is -0 and y is +0, return true.
vi. Return false.
d. If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions). Otherwise, return false.
e. If Type(x) is Boolean, return true if x and y are both true or both false. Otherwise, return false.
f. Return true if x and y refer to the same object. Otherwise, return false.
If x is null and y is undefined, return true.
If x is undefined and y is null, return true.
If Type(x) is Number and Type(y) is String, return the result of the comparison
x == ToNumber(y).
If Type(x) is String and Type(y) is Number, return the result of the comparison
ToNumber(x) == y.
If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
If Type(x) is either String or Number and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.
Return false.
Note that in the spec, the Type of a primitive string object is String, whereas the type of any object (including the String object) is Object.
With === the relevant line is #1: the Type of the objects are different, so false is returned.
With == the relevant line is #8: x is a String ("Hello world!") and y is an Object (The String object containing the string "Hello world!"). Thus the comparison x == ToPrimitive(y) is made. ToPrimitive ends up calling the valueOf method of the object, or if that method doesn't exist, the toString method. In this case, a String object's valueOf method returns the primitive string the object contains. Thus the equality operation is done again, this time between two primitive strings which contain the same text, which returns true thanks to #1.d.
JavaScript is a bit messy under the hood...
EDIT: Notice that if two objects are compared, no conversions apply, but rather, rule #1.f applies. Thus, thanks to the spec, I was able to correctly predict the output of the following code:
> new String("hi") == new String("hi")
false
EDIT: Just thought I'd add that these distinctions are even further blurred by more implicit type conversion. For example, the following works:
> ("hi").toString()
"hi"
but that's not because "hi" is an object (like in Python):
> typeof "hi"
"string"
But rather, because the . operator does a conversion from the primitive string type to the string Object type (creating a new string object) whose toString method is then called.
This behaviour is detailed in the ECMAScript 5 specification, 15.5.1 and 15.5.2:
When String is called as a function rather than as a constructor, it performs a type conversion.
...
Returns a String value (not a String object) computed by ToString(value). If value is not supplied, the empty String "" is returned.
So String("some string") creates a string value.
When String is called as part of a new expression, it is a constructor: it initialises the newly created object.
So new String("some string") creates an instance of the String object.
And to actually answer your questions:
Is this standard behavior?
Yes, for the reasons detailed above.
If so, what are the respective types of t1 and t2
You can check this with the typeof operator:
console.log(typeof t1); //string
console.log(typeof t2); //object
This is happening because the == operator only checks if the values are the same, whereas === checks both the value and type. new String("Hello world!") is not actually being given the type string, it is an object, while String("Hello world!") is actually a string.
The first example String("Hello world!)" creates a primitive string while the second example new String("Hello world!") creates an String object.