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');
}
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?
Share Improve this question edited Apr 26, 2018 at 6:52 Durga 15.6k2 gold badges30 silver badges54 bronze badges asked Apr 26, 2018 at 6:44 NaveenNaveen 3713 silver badges9 bronze badges 4- stackoverflow./questions/359494/… – gvmani Commented Apr 26, 2018 at 6:45
- 1 Possible duplicate of Which equals operator (== vs ===) should be used in JavaScript parisons? – user9420984 Commented Apr 26, 2018 at 6:46
- 1 Doesn't print anything for me – Jagdeep Singh Commented Apr 26, 2018 at 6:46
- 2 I don't think that would be evaluated to true. – Jai Commented Apr 26, 2018 at 6:49
7 Answers
Reset to default 2Happen 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
When you do ==
it is not a strict parison so what it does for the condition a == 3 && a == 4
, is that first it pares a == 3
. Since, it is not a strict parison, 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 parison 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.
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 paring 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 parisons and sameness
In this URL refer 'Loose equality using ==' section.
In you case your parison as a == 3. a is object and 3 is number. So parison 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
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744717816a4589725.html
评论列表(0条)