嘿, 我是Mofei!
JavaScript Object Conversion: toString and valueOf

Before starting this topic, let’s look at a few examples below:

parseInt(0.0000004)  // 4
![]==[] //true
['x','y'] == 'x,y' //true
alert({name:'mofei'})  //"[object Object]"

Sometimes the results leave me stunned, why is that? Today we will discuss JavaScript object conversion.

Primitive Types

First, let’s understand the “primitive types” in JavaScript:

Number

String

Boolean

When comparing or performing various operations in JavaScript, objects are converted into these types for further operations, and we will explain them one by one:

String Conversion

When an operation or calculation needs a string, it often triggers the String conversion of the Object. For example:

var obj={name:'Mofei'}
var str = ' ' + obj
console.log(str);  //   [object Object]

In the above example, during the string addition process, the system calls the obj's String conversion, the specific rules are as follows:

  1. If the toString method exists and returns a “primitive type”, return the result of toString.
  2. If the toString method does not exist or does not return a “primitive type”, call the valueOf method. If the valueOf method exists and returns “primitive type” data, return the result of valueOf.
  3. In other cases, throw an error.

We can simply prove the above rules in the following way:

First, we try to rewrite an object's toString method:

var a={
    toString:function(){
        console.log('Called a.toString');
        return '111';
    }
}
alert(a);

//Called a.toString
// 111

As we can see, when executing ' '+a, the system automatically called a's toString method, converting a (Object) to a String.

Next, we will try to prove that if the toString() method is unavailable, the system will call the valueOf() method:

var a={
    toString:function(){
        console.log('Called a.toString');
        return '111';
    },
    valueOf:function(){
        console.log('Called a.valueOf');
        return '111';
    }
}
alert(a);

//Called a.toString

Here we added the valueOf method, but found that the system did not call it because, in the first step, toString returned a primitive type. Let’s attempt to change the first step return value to an object {}:

var a={
    toString:function(){
        console.log('Called a.toString');
        return {};
    },
    valueOf:function(){
        console.log('Called a.valueOf');
        return '111';
    }
}
alert(a);

// Called a.toString
// Called a.valueOf

From the results, we can see that when toString is unavailable, the system will then try the valueOf method. Now let’s modify the valueOf method to also return an object {}:

var a={
    toString:function(){
        console.log('Called a.toString');
        return {};
    },
    valueOf:function(){
        console.log('Called a.valueOf');
        return {};
    }
}
alert(a);

// Called a.toString
// Called a.valueOf
//  Uncaught TypeError: Cannot convert object to primitive value

We can find that if both toString and valueOf methods are unavailable, the system will directly return an error.

Number Conversion

Next, let’s talk about Number conversion. Similarly, when a Number is needed (such as Math.sin()), the interpreter will attempt to convert the object into a Number object.

The following situations will typically trigger Number conversion:

  1. Method parameters need a Number, e.g., Math.sin(obj), etc.
  2. During comparisons, e.g., obj == 'abc'
  3. During calculations, e.g., obj + 123

The conversion rules are as follows:

  1. If valueOf exists and returns “primitive type” data, return the result of valueOf.
  2. If toString exists and returns “primitive type” data, return the result of toString.
  3. Throw an error.

Refer to the method of String conversion for verification. Here we only list one typical method; others can be modified manually:

var a={
    toString:function(){
        console.log('Called a.toString');
        return 12;
    },
    valueOf:function(){
        console.log('Called a.valueOf');
        return {};
    }
}
a+1
//Called a.valueOf
//Called a.toString
//13

As we can see, we modified the valueOf and toString methods. The system called the valueOf method but found the returned value was not “primitive type” data, so it tried calling the toString method again and returned the value 12 from that method, finally making +1 result in 13.

Boolean Conversion

During boolean comparisons, like if(obj), while(obj), etc., Boolean conversion will occur, and the rules are as follows:

Value Boolean Value
true/false true/false
undefined,null false
Number 0,NaN corresponds to false, others correspond to true
String "" corresponds to false, others correspond to true ('0' corresponds to true)
Object true

Here’s a typical example:

[] == ![]  //true

// First, the right side is a logical evaluation ![], so it first converts to boolean
// [] == !true
// [] == false
// The left side is not a primitive type, trying to convert the left side into primitive type, changing to
// '' == false
// Converted to Number
// 0 == 0

Summary

From the above introduction, the questions mentioned at the beginning should be easily answered now.

parseInt(0.0000004)  // 4
![]==[] //true
['x','y'] == 'x,y' //true
alert({name:'mofei'})  //"[object Object]"

Regarding these conversions, it can indeed be perplexing at times. However, after understanding the principles, it becomes much easier. If you have any questions, feel free to leave a message, and I will reply as soon as possible.

THE END

More Articles You Might Be Interested In

Did this post inspire any ideas? Share your thoughts in the comments!

avatar

Mofei's Friend (Click to edit)

Give me some inspiration!

HI. I AM MOFEI!

NICE TO MEET YOU!