If you can answer yes, congratulations, you can make a detour

preface

Some people will say, “This is a weird problem, in other languages, if this can output true, it is estimated to be a ghost, but you don’t say, in JS, it is possible. One person recently asked a question on Twitter:

  • Can (a==1 && a==2 && a==3) ever evaluate to true?
  • Answer: yes

In this article, I’ll explain how this code works:

const a = {
  num: 0.valueOf: function() {
    return this.num += 1}};const equality = (a==1 && a==2 && a==3);
console.log(equality); // true
Copy the code

You can open the Chrome browser, open developer mode, type this code in the console, and see the output ([Windows]: Ctrl + Shift + J [MAC]: Cmd + Opt + J).

What’s the trick?

In fact, there is no, there are two concepts in JS:

  • Implicit conversion
  • The valueOf function of object

Implicit conversion

Note: in this problem, we use == instead of ===, in js == represents equal, not congruent, then there is the implicit transformation problem of variables. That means there are more possibilities than we might expect. There are a lot of articles about implicit transformations in JS. I recommend the following blogs, if you want to learn more, you can check them out:

Recommend the blog

valueOf

JavaScript provides a way to convert an Object to its original value: object.prototype.valueof (), which by default returns the Object being called.

Here’s an example:

const a = {
  num: 0
}
Copy the code

We can use the valueOf method on the above object and it will return an object.

a.valueOf();
// {num: 0}
Copy the code

We can use typeOf to check the typeOf the output:

typeof a.valueOf();
// "object"
Copy the code

To make it easier for valueOf to convert an object to its original value, we can override it. In other words, we can use valueOf to return a string, number, Boolean, etc. Instead of an object, we can look at the following code:

a.valueOf = function() {
  return this.num;
}
Copy the code

We’ve overridden the native valueOf() method. When we call valueOf, it returns a.sum. Let’s now run the following:

a.valueOf();
/ / 0
Copy the code

We get 0, which makes sense, because 0 is the value assigned to A. um. So let’s run a few tests:

typeof a.valueOf();
// "number"

a.num == a.valueOf()
// true
Copy the code

Good, but why is this important?

This is important because when you encounter an equal operator for two different types, JS converts it — it attempts to convert the operands to similar types.

In our problem :(a==1 && a==2 && a==3)JavaScript will attempt to convert the object to a numeric type for comparison. JavaScript calls the valueOf() method when an Object is being converted.

Since we changed the valueOf() method, can we do the following:

a == 0

// true
Copy the code

We did it. It was easy.

Now one thing we need to do is change the value of a every time we call it.

Fortunately, there is a += symbol in JavaScript.

The += operator makes it easy to change a value. Let’s take a simple example:

let b = 1
console.log(b+=1); / / 2
console.log(b+=1); / / 3
console.log(b+=1); / / 4
Copy the code

As you can see, every time we use the addition assignment operator, we can increment our variable.

So we can apply this concept to valueOf().

a.valueOf = function() {
  return this.num += 1;
}
Copy the code

Every time we call valueOf, it returns the variable increaled by 1.

With this change, let’s run the following code:

const equality = (a==1 && a==2 && a==3);
console.log(equality); // true
Copy the code

That’s how it works.

Remember the following two points:

  • Using the equality operator, js does a cast
  • Each time our object calls valueOf(), its value increases by one

So we’re going to get true every time we compare.

  • Add the operation process of the second point
a                     == 1   -> 
a.valueOf()           == 1   -> 
a.num += 1= =1   -> 
0+ =1= =1   ->
1= =1   -> true
a                     == 2   -> 
a.valueOf()           == 2   -> 
a.num += 1= =2   -> 
1+ =1= =2   ->
2= =2   -> true
a                     == 3   -> 
a.valueOf()           == 3   -> 
a.num += 1= =3   -> 
2+ =1= =3   ->
3= =3   -> true
Copy the code

conclusion

Thank you for watching this little experiment, I hope you can learn something from it, if you are interested in it, you can also go to my Github and click the star, your support is my continuous output of power, thank you!!