I would like to understand the weird behaviour of JavaScript identity and equality operator as given below.
var a = {};
var b = {};
a === b; //false
a == b; //false
var c = '';
var d = '';
c === d; //true
c == d; //true
All four variables a ,b ,c and d are objects. But when comparing them, first case yields false whereas second one true.
I studied comparison from the following source: https://msdn.microsoft.com/en-us/library/d53a7bd4(v=vs.94).aspx
According to the above article, except number and boolean everything is compared by reference instead of value. So how the first case returns false and second one true.
c and d in your example are strings, which are primitive types in JavaScript and compared by value.
For this reason, c == d returns true.
The article is talking about string objects created usng the new String('foo') constructor, which actually creates objects. In this case, the references are compared, returning false.
console.log(new String('foo') == new String('foo')) // false
console.log('foo' == 'foo') // true
A (primitive) string is a value type (like Number). As such === compares its value (equality).
Objects are reference types, and for them === compares identity.
Strings are a bit crazy, as there are both primitive strings and String objects (created with new String("foo")).
== works the same way as === except that it does type conversions to "make things equal if possible". For reference types this is the same as ===, except that it also equates primitive strings and String objects.
"abc" == new String("abc");
"abc" !== new String("abc");
Related
I know == operator performs the type coercion. But I can't understand the below behaviour.
const x = new Boolean(false);
if (x) {
console.log("if(x) is true");
}
if (x == false) {
console.log("if(x == false) is true");
}
Surprisingly, above snippet prints both lines:
if(x) is true
if(x == false) is true
Can someone explain this weird behaviour or there is something fundamental I'm missing?
As mentioned by other answers, that's because x is an Object – a Boolean object, but still an object, since you're using the new operator – and is coerced only when you compare x to false: the if (x) is checking if x is a truthy value, and therefore doesn't need coercion (there are no other operands involved): an object is always "true" (weeeell… almost always: typeof null returns object but it's a falsy value. But that's another story…).
You can easily checking when the coercion is invoked tapping the toPrimitive symbol:
var x = new Boolean(false);
// first of all, if it wasn't an object you couldn't
// do this
x[Symbol.toPrimitive] = function(hint) {
console.log({hint});
return this.valueOf();
}
// no console.log yet
if (x) {
console.log("if(x) is true");
}
// here you got the console.log before the one
// inside the block, since the coercion happens
// in the `if`
if (x == false) {
console.log("if(x == false) is true");
}
new Boolean(false) produces an object. Objects are always truthy even if they wrap a falsy primitive value. For example, new String("") is also truthy despite "" being falsy.
On the other hand, when you do new Boolean(false) == false, it coerces the object to its primitive value for the comparison. Incidentally, new Boolean(false) === false is not true, since their types don't match.
As a general rule, you shouldn't use object constructors for primitive types unless you have a specific reason for it, to avoid unexpected behavior like this.
when you do if (expression) in javascript the expression is evaluated by being cast to a boolean.
Somewhat confusingly, Boolean(new Boolean(false)) evaluates to true because as Nick said it is still an object. This is what is causing the behaviour you're confused about.
Good read for more info https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/
If you write
const x = new Boolean(false);
typeof x will return object. The type object is "truthy", which means it evaluates to true if there's no operator like ==. However, the value of it is false, which is why the second statement evaluates to true as well.
So the if statements behave differently, because the if without operator checks whether the type is truthy or falsy (in this case truthy -> true) and the if with the comparison (==) calls .valueOf() which is false.
You shouldn't be using new wrappers for this scenario anyway.
const x = false;
is enough. For casting, you can use Boolean() without new wrapper.
To check whether a value is truthy, you can use a double negation:
const x = new Boolean(false);
if (x) console.log(!!x);
if (x == false) console.log(x.valueOf());
You should be using Boolean(false) instead of new Boolean(false), since Boolean is a function.
Otherwise you get an empty object {}, which is not the same type as what is returned by the function itself, which is a boolean.
const x = new Boolean(false);
const y = Boolean(false);
console.log(x, typeof x);
console.log(y, typeof y);
In the your first test, you only check if the value is truthy, and an empty object is truthy, since x = {}, the test passes:
const x = new Boolean(false);
console.log(x, !!x, !!{}, Boolean(x))
if (x) {
console.log("if(x) is true");
}
However, when using ==, the operator coerces new Boolean(false) to its primitive value using x.valueOf which is false and thus the equality passes.
const x = new Boolean(false);
console.log(x.valueOf())
Just curious:
4 instanceof Number => false
new Number(4) instanceof Number => true?
Why is this? Same with strings:
'some string' instanceof String returns false
new String('some string') instanceof String => true
String('some string') instanceof String also returns false
('some string').toString instanceof String also returns false
For object, array or function types the instanceof operator works as expected. I just don't know how to understand this.
[new insights]
Object.prototype.is = function() {
var test = arguments.length ? [].slice.call(arguments) : null
,self = this.constructor;
return test ? !!(test.filter(function(a){return a === self}).length)
: (this.constructor.name ||
(String(self).match ( /^function\s*([^\s(]+)/im )
|| [0,'ANONYMOUS_CONSTRUCTOR']) [1] );
}
// usage
var Newclass = function(){}; // anonymous Constructor function
var Some = function Some(){}; // named Constructor function
(5).is(); //=> Number
'hello world'.is(); //=> String
(new Newclass()).is(); //=> ANONYMOUS_CONSTRUCTOR
(new Some()).is(); //=> Some
/[a-z]/.is(); //=> RegExp
'5'.is(Number); //=> false
'5'.is(String); //=> true
value instanceof Constructor is the same as Constructor.prototype.isPrototypeOf(value) and both check the [[Prototype]]-chain of value for occurences of a specific object.
Strings and numbers are primitive values, not objects and therefore don't have a [[Prototype]], so it'll only work if you wrap them in regular objects (called 'boxing' in Java).
Also, as you noticed, String(value) and new String(value) do different things: If you call the constructor functions of the built-in types without using the new operator, they try to convert ('cast') the argument to the specific type. If you use the new operator, they create a wrapper object.
new String(value) is roughly equivalent to Object(String(value)), which behaves the same way as new Object(String(value)).
Some more on types in JavaScript: ECMA-262 defines the following primitive types: Undefined, Null, Boolean, Number, and String. Additionally, there is the type Object for things which have properties.
For example, functions are of type Object (they just have a special property called [[Call]]), and null is a primitive value of type Null. This means that the result of the typeof operator doesn't really return the type of a value...
Aditionally, JavaScript objects have another property called [[Class]]. You can get it via Object.prototype.toString.call(value) (this will return '[objectClassname]'). Arrays and functions are of the type Object, but their classes are Array and Function.
The test for an object's class given above works when instanceof fails (e.g. when objects are passed between window/frame boundaries and don't share the same prototypes).
Also, you might want to check out this improved version of typeof:
function typeOf(value) {
var type = typeof value;
switch(type) {
case 'object':
return value === null ? 'null' : Object.prototype.toString.call(value).
match(/^\[object (.*)\]$/)[1]
case 'function':
return 'Function';
default:
return type;
}
}
For primitives, it will return their type in lower case, for objects, it will return their class in title case.
Examples:
For primitives of type Number (eg 5), it will return 'number', for wrapper objects of class Number (eg new Number(5)), it will return 'Number';
For functions, it will return 'Function'.
If you don't want to discern between primitive values and wrapper objects (for whatever, probably bad reason), use typeOf(...).toLowerCase().
Known bugs are some built-in functions in IE, which are considered 'Object' and a return value of 'unknown' when used with some COM+ objects.
You may try to evaluate:
>>> typeof("a")
"string"
>>> typeof(new String("a"))
"object"
>>> typeof(4)
"number"
>>> typeof(new Number(4))
"object"
As stated in Christoph's answer, string and number literals are not the same as String and Number objects. If you use any of the String or Number methods on the literal, say
'a string literal'.length
The literal is temporarily converted to an object, the method is invoked and the object is discarded.
Literals have some distinct advantages over objects.
//false, two different objects with the same value
alert( new String('string') == new String('string') );
//true, identical literals
alert( 'string' == 'string' );
Always use literals to avoid unexpected behaviour!
You can use Number() and String() to typecast if you need to:
//true
alert( Number('5') === 5 )
//false
alert( '5' === 5 )
In the case of primitive numbers, the isNaN method could also help you.
This is a nuance of Javascript which I've found catches some out. The instanceof of operator will always result in false if the LHS is not an object type.
Note that new String('Hello World') does not result in a string type but is an object. The new operator always results in an object. I see this sort of thing:
function fnX(value)
{
if (typeof value == 'string')
{
//Do stuff
}
}
fnX(new String('Hello World'));
The expectation is that "Do Stuff" will happen but it doesn't because the typeof the value is object.
With reference to below code written in Javascript.
let a = {
value: 2,
toString: function() {
return ++this.value;
}
}
if (a == 3 && a == 4) {
console.log('Condition is true');
}
The output is "Condition is true". Looks like it invokes toString() function. But how?
When I replace "==" with "===", condition does not evaluates to true and it does not invoke toString() function this time?
Can someone explain me in detail what's going under the hood?
When you do == it is not a strict comparison so what it does for the condition a == 3 && a == 4, is that first it compares a == 3. Since, it is not a strict comparison, it will change a to string. And since you have toString() in a, that will increment the value of a from 2 to 3 and hence a == 3 result in true. Then, a == 4 checks the same way and this time the value of a is 3 so when it checks for a == 4 it results in true by invoking the toString() function of a.
let a = {
value: 2,
toString: function() {
return ++this.value;
}
}
if (a == 3 && a == 4) {
console.log('Condition is true');
}
However, when you use ===, it works as a strict comparison and the type of LHS should match RHS. Thus, a is a object in LHS and there is a number type in RHS, so it results false for a == 3 and hence, a == 3 && a == 4
let a = {
value: 2,
toString: function() {
return ++this.value;
}
}
if (a === 3 && a === 4) {
console.log('Condition is true');
} else {
console.log('Condition is false');
}
The output is "Condition is true". Looks like it invokes 'toString()'
function.
Everytime you use == operator between two variables with different types it is invoked internally toString method which will coerce one member. Have a look at type coercion
But how?
You're creating a custom toString function for your a object that changes what it returns each time it is used such that it satisfies all two conditions.
You can also use valueOf method.
How about === operator ?
Otherwise, the === operator will not do the conversion.
What means this ?
If you're using === operator with two values with different type === will simply return false.
Happen to notice that toString is invoked in interpolated string, executed prioritized than valueOf
var a = {
value: 1000,
toString: () => 'call toString method',
valueOf: () => 'call valueOf method'
};
console.log(`interpreted value: ${a}`); // interpreted value: call toString method
In addition to Mihai's answer, === is a strict typechecking equality operator which checks for the type of the operands and the values as well.
In your case, the type of a is an object, whereas 3 and 4 are numbers. So the condition doesn't evaluate to true.
it checks whether object has falsy value or not when you use == thats why you get true from a == 4 and a == 3. Have a look at type coercion. It does not coerce variables when comparing them and thats why you cannot get into the block statement
You can find detail information of how '==' and '===' works in javascript from link below:
Equality comparisons and sameness
In this URL refer 'Loose equality using ==' section.
In you case your comparison as a == 3. a is object and 3 is number. So comparison will take place as ToPrimitive(a) == 3. What ToPrimitive(a) do is it attempting to invoke varying sequences of a.toString and a.valueOf methods on A. This is how your toString function is called.
On the surface your question looks like the sheer difference between == and === operators, but in fact there is bit more to it.
For your first question, since javascript is not strictly typed language, there is 2 operators, == will try to convert the left operand to right ones type if possible whereas === will give false if the types are different with the exception of NaN.
A more interesting question is when toString method gets called. Normally when you create an object, either by typing an object literal or through a constructor, it will inherit toString from the Object, you easily check this:
var u = function(){};
var w = {};
u.prototype.toString === Object.prototype.toString //true
w.toString === Object.prototype.toString //true as well
Now what you might forget is that there is also a valueOf method:
u.prototype.valueOf === Object.prototype.valueOf //true
w.valueOf === Object.prototype.valueOf //true as well
But what does it do? I points to itself:
w.valueOf === w //true
u.prototype.valueOf() === u.prototype //true as well
So when an object is given, the first choice is to use the toString becuae valueOf will result in the object itself. What does toString give by default? it can depend on what is there on its prototype chain:
w.toString() //"[object Object]"
u.toString() //"function (){}"
u.prototype.toString.call(u) //"[object Function]"
So by default the first choice is to use the nearest toString method of the object. Now to see what happens if we override BOTH valueOf and toString, let me construct this object:
var x = {
inner:10,
ledger:[],
result:[],
timeout:0,
toString:function(){
console.log("String");
clearTimeout(this.timeout);
this.timeout = setTimeout((function(){
this.result = this.ledger;
this.ledger = []}).bind(this)
,0) ;
this.ledger.push("toString");
this.ledger.slice(-2);
return String(this.inner);
},
valueOf:function(){
console.log("Valueof");
clearTimeout(this.timeout);
this.timeout = setTimeout((function(){
this.result = this.ledger;
this.ledger = []}).bind(this)
,0) ;
this.ledger.push("valueOf");
this.ledger.slice(-2);
return this.inner;
}
}
This object will keep a "ledger", an array of valueOf or toString or both called during type conversion. It will also console.log. So,here are some operations that will trigger type conversion just like ==:
+x //10
//ValueOf
"5" + x //"510"
//ValueOf
x + [] //10
//ValueOf
x + "str"//"10str"
//ValueOf
x.toString() //"10"
//String
String(x) //"10"
//String
x + {u:""} //"10[object Object]"
//valueOf
So in many cases if a non-default valueOf is found that is used. If the right operand is a string, then the returned value from valueOf is converted to string rather than toString on the object. To override default behavior you can force call to string by using toString or String( as shown in the examples. So the priority list goes as:
Custom valueOf >> custom toString >> default toString >>>> default valueOf
How to check in the most simple way if two objects are equal? I noticed that there's no method ExactEqual()-like, so I wonder if I should do it manually or not.
Thanks for any help!
There is no such method. Take a look at this jqfaq.com link where it was discussed and given the best way to check. This will suitable for both typescript and javascript. Hope, that will help you!.
To quote the most important part of that answer:
//“===” means that they are identical.
//“==” means that they are equal in value.
//( == )
//Each JavaScript value is of a specific “type” (Numbers, strings, Booleans, functions, and objects). So if you try to compare a string with a number, the browser will try to convert the string into a number before doing the comparison.
//So the following will return true.
55 == “55″ //true
0 == false //true
1 == true //true
//(===)
//The === operator will not do the conversion, if two values are not the same type it will return false. In other words, this returns true only if the operands are strictly equal in value or if they are identical objects.
55 === “55″ //false
0 === false //false
1 === true //false
var a = [1, 2, 3];
var b = [1, 2, 3];
var c = a;
var is_ab_eql = (a === b); // false (Here a and b are the same type,and also have the same value)
var is_ac_eql = (a === c); // true.
//Value types (numbers):
//a === b returns true if a and b have the same value and are of the same type.
//Reference types:
//a === b returns true if a and b reference the exact same object.
//Strings:
//a === b returns true if a and b are both strings and contain the exact same characters.
var a = “ab” + “c”;
var b = “abc”;
a === b //true
a == b //true
//in thiss case the above condition will fail
var a = new String(“abc”);
var b = “abc”;
a === b //false
a == b// true
//… since a and b are not a same type.
typeof “abc”; // ‘string’
typeof new String(“abc”)); // ‘object
Just curious:
4 instanceof Number => false
new Number(4) instanceof Number => true?
Why is this? Same with strings:
'some string' instanceof String returns false
new String('some string') instanceof String => true
String('some string') instanceof String also returns false
('some string').toString instanceof String also returns false
For object, array or function types the instanceof operator works as expected. I just don't know how to understand this.
[new insights]
Object.prototype.is = function() {
var test = arguments.length ? [].slice.call(arguments) : null
,self = this.constructor;
return test ? !!(test.filter(function(a){return a === self}).length)
: (this.constructor.name ||
(String(self).match ( /^function\s*([^\s(]+)/im )
|| [0,'ANONYMOUS_CONSTRUCTOR']) [1] );
}
// usage
var Newclass = function(){}; // anonymous Constructor function
var Some = function Some(){}; // named Constructor function
(5).is(); //=> Number
'hello world'.is(); //=> String
(new Newclass()).is(); //=> ANONYMOUS_CONSTRUCTOR
(new Some()).is(); //=> Some
/[a-z]/.is(); //=> RegExp
'5'.is(Number); //=> false
'5'.is(String); //=> true
value instanceof Constructor is the same as Constructor.prototype.isPrototypeOf(value) and both check the [[Prototype]]-chain of value for occurences of a specific object.
Strings and numbers are primitive values, not objects and therefore don't have a [[Prototype]], so it'll only work if you wrap them in regular objects (called 'boxing' in Java).
Also, as you noticed, String(value) and new String(value) do different things: If you call the constructor functions of the built-in types without using the new operator, they try to convert ('cast') the argument to the specific type. If you use the new operator, they create a wrapper object.
new String(value) is roughly equivalent to Object(String(value)), which behaves the same way as new Object(String(value)).
Some more on types in JavaScript: ECMA-262 defines the following primitive types: Undefined, Null, Boolean, Number, and String. Additionally, there is the type Object for things which have properties.
For example, functions are of type Object (they just have a special property called [[Call]]), and null is a primitive value of type Null. This means that the result of the typeof operator doesn't really return the type of a value...
Aditionally, JavaScript objects have another property called [[Class]]. You can get it via Object.prototype.toString.call(value) (this will return '[objectClassname]'). Arrays and functions are of the type Object, but their classes are Array and Function.
The test for an object's class given above works when instanceof fails (e.g. when objects are passed between window/frame boundaries and don't share the same prototypes).
Also, you might want to check out this improved version of typeof:
function typeOf(value) {
var type = typeof value;
switch(type) {
case 'object':
return value === null ? 'null' : Object.prototype.toString.call(value).
match(/^\[object (.*)\]$/)[1]
case 'function':
return 'Function';
default:
return type;
}
}
For primitives, it will return their type in lower case, for objects, it will return their class in title case.
Examples:
For primitives of type Number (eg 5), it will return 'number', for wrapper objects of class Number (eg new Number(5)), it will return 'Number';
For functions, it will return 'Function'.
If you don't want to discern between primitive values and wrapper objects (for whatever, probably bad reason), use typeOf(...).toLowerCase().
Known bugs are some built-in functions in IE, which are considered 'Object' and a return value of 'unknown' when used with some COM+ objects.
You may try to evaluate:
>>> typeof("a")
"string"
>>> typeof(new String("a"))
"object"
>>> typeof(4)
"number"
>>> typeof(new Number(4))
"object"
As stated in Christoph's answer, string and number literals are not the same as String and Number objects. If you use any of the String or Number methods on the literal, say
'a string literal'.length
The literal is temporarily converted to an object, the method is invoked and the object is discarded.
Literals have some distinct advantages over objects.
//false, two different objects with the same value
alert( new String('string') == new String('string') );
//true, identical literals
alert( 'string' == 'string' );
Always use literals to avoid unexpected behaviour!
You can use Number() and String() to typecast if you need to:
//true
alert( Number('5') === 5 )
//false
alert( '5' === 5 )
In the case of primitive numbers, the isNaN method could also help you.
This is a nuance of Javascript which I've found catches some out. The instanceof of operator will always result in false if the LHS is not an object type.
Note that new String('Hello World') does not result in a string type but is an object. The new operator always results in an object. I see this sort of thing:
function fnX(value)
{
if (typeof value == 'string')
{
//Do stuff
}
}
fnX(new String('Hello World'));
The expectation is that "Do Stuff" will happen but it doesn't because the typeof the value is object.