3

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?

Durga
  • 15,263
  • 2
  • 28
  • 52
Naveen
  • 351
  • 3
  • 9
  • https://stackoverflow.com/questions/359494/which-equals-operator-vs-should-be-used-in-javascript-comparisons?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa – gvmani Apr 26 '18 at 06:45
  • 1
    Possible duplicate of [Which equals operator (== vs ===) should be used in JavaScript comparisons?](https://stackoverflow.com/questions/359494/which-equals-operator-vs-should-be-used-in-javascript-comparisons) –  Apr 26 '18 at 06:46
  • 1
    Doesn't print anything for me – Jagdeep Singh Apr 26 '18 at 06:46
  • 2
    I don't think that would be evaluated to true. – Jai Apr 26 '18 at 06:49

7 Answers7

1

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.

Mihai Alexandru-Ionut
  • 47,092
  • 13
  • 101
  • 128
  • `The output is "Condition is true".` Any explanations about it? – Jai Apr 26 '18 at 06:51
  • Just for future readers: _"Everytime you use `==` operator between two variables with different types it is invoked internally `toString` method"_ [is not true](http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3) when, e.g., comparing a number to a string. – Arjan Jul 10 '19 at 17:00
1

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');
}
Ankit Agarwal
  • 30,378
  • 5
  • 37
  • 62
1

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
ROROROOROROR
  • 959
  • 1
  • 14
  • 31
0

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.

31piy
  • 23,323
  • 6
  • 47
  • 67
0

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

suchcodemuchwow
  • 848
  • 2
  • 9
  • 27
0

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.

Karan
  • 12,059
  • 3
  • 24
  • 40
0

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

ibrahim tanyalcin
  • 5,643
  • 3
  • 16
  • 22
  • Just for future readers: _"`==` will try to convert the left operand to right ones type if possible"_ is true for the example code (where the right operand is a number), [but not in general](http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3). – Arjan Jul 10 '19 at 16:47