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