Comprehensively analyze toString and valueof, and solve several necessary interview questions for large factories

Time:2021-2-17

Hello, I’m Li Bai~~

Recently, the weather in Shenzhen is changeable. Sometimes it rains cats and dogs, sometimes it’s sunny. I hope it will rain continuously for a few days. How nice~~

The frightening summer may be over. No one knows what happened to you this summer or this year, but I know.

Know that you work hard, or you may be slow. But in the face of autumn, in the face of the upcoming National Day holiday, please continue to work hard, not only the flow of life, there is time, come on~~

Today, as an author and reader, I hand in my homework for myself and on the way to technical learning~~

Now, let’s get to the point and understand what these two methods do

Basically, all JS data types have these two methods, except null. They are methods on the prototype chain, and also to solve the problem of JavaScript value operation and display.

valueOfandtoStringAlmost all of them are operators(+-*/==><)Is called (implicit conversion).

toString

Returns a string representing the object. The toString method is called automatically when the object is represented as a text value or referenced as an expected string.

1. Call manually to see what effect

Well, it’s the same as the introduction. It’s not deceptive. It’s all converted into strings.

What’s special is that when you represent an object, it becomes[object Object]When it represents an array, it becomes a string with the contents of the array connected by commas, which is equivalent toArray.join(',')

let a = {}
let b = [1, 2, 3]
let c = '123'
let d = function(){ console.log('fn') }

console.log(a.toString())   // '[object Object]'
console.log(b.toString())   // '1,2,3'
console.log(c.toString())   // '123'
console.log(d.toString())   // 'function(){ console.log('fn') }'

2. The most accurate type judgment

This belongs to a more accurate way of judgment, in some cases than usingtypeof & instanceofIt’s more efficient and accurate.

toString.call(()=>{})       // [object Function]
toString.call({})           // [object Object]
toString.call([])           // [object Array]
toString.call('')           // [object String]
toString.call(22)           // [object Number]
toString.call(undefined)    // [object undefined]
toString.call(null)         // [object null]
toString.call(new Date)     // [object Date]
toString.call(Math)         // [object Math]
toString.call(window)       // [object Window]

3. When will it be called automatically

When using the operator, if one side is an object, it will be called firsttoStingMethod, that isImplicit transformationAnd then do the operation.

let c = [1, 2, 3]
let d = {a:2}
Object.prototype.toString = function(){
    console.log('Object')
}
Array.prototype.toString = function(){
    console.log('Array')
    return  this.join (',') // returns the default value of toString (test below)
}
console.log(2 + 1)  // 3
console.log('s')    // 's'
console.log('s'+2)  // 's2'
console.log (C < 2) // false (once = >'array ')
console.log (c + C) // 1,2,31,2,3 (twice = >'array ')
console.log (d > d) // false (twice = >'object ')

4. RewritetoStringmethod

Now that I know, there is a problemtoStringThis default method, we can also override this method

class A {
    constructor(count) {
        this.count = count
    }
    toString() {
        Return 'I have so much money:'+ this.count
    }
}
let a = new A(100)

console.log(a)              // A {count: 100}
console.log (a.tostring()) // I have so much money: 100
console.log (a + 1) // I have so much money: 1001

Nice.

valueOf

Returns the original value of the current object.

Specific functions and functionstoStringSimilar, also has the above automatic call and rewrite method.

Here is nothing to say, mainly for the difference between the two, please continue to look down

let c = [1, 2, 3]
let d = {a:2}

console.log(c.valueOf())    // [1, 2, 3]
console.log(d.valueOf())    // {a:2}

The difference between the two

  • What’s common: it’s called automatically when you output objects.
  • difference:The default return values are different, and there is a priority relationship

In the case of coexistence of the two, thenumerical valueIn the operation, the priority is calledvalueOfcharacter stringIn the operation, the priority is calledtoString

Look at the code

class A {
    valueOf() {
        return 2
    }
    toString() {
        Return 'hahaha'
    }
}
let a = new A()

console.log (string (a)) //'ha ha '= > (toString)
console.log(Number(a))  // 2         => (valueOf)
console.log(a + '22')   // '222'     => (valueOf)
console.log(a == 2)     // true      => (valueOf)
console.log (a = = = 2) // false = > (strictly equal to not trigger implicit conversion)

The result gives the impression that if converted to a string, thetoStringMethod, called if it is converted to a numeric valuevalueOfmethod.

But some of thema + '22'Very discordant, string combination should be calledtoStringmethod. In order to find out the truth, we need more rigorous experiments.

  • Let’s take a look at it for a momentvalueOfMethod remove
class A {
    toString() {
        Return 'hahaha'
    }
}
let a = new A()

console.log (string (a)) //'ha ha '= > (toString)
console.log(Number(a))  // NaN         => (toString)
console.log (a +'22 ') /'hahaha 22' = > (toString)
console.log(a == 2)     // false       => (toString)
  • RemovetoStringLook at the method
class A {
    valueOf() {
        return 2
    }
}
let a = new A()

console.log(String(a))  // '[object Object]'    => (toString)
console.log(Number(a))  // 2                    => (valueOf)
console.log(a + '22')   // '222'                => (valueOf)
console.log(a == 2)     // true                 => (valueOf)

It’s different, isn’t it?! It’s not like abovetoStringSo unified and regular.
For that[object Object]I guess it’s fromObjectIt’s inherited from there. Let’s take it out.

class A {
    valueOf() {
        return 2
    }
}
let a = new A()

Object.prototype.toString = null; 

console.log(String(a))  // 2        => (valueOf)
console.log(Number(a))  // 2        => (valueOf)
console.log(a + '22')   // '222'    => (valueOf)
console.log(a == 2)     // true     => (valueOf)

Conclusion:valueOfIt’s biased towards computation,toStringIt tends to show.

  1. During object transformation, thetoStringMethod, if not overriddentoString, will callvalueOfMethod; if neither method is overridden, pressObjectOftoStringOutput.
  2. In progressStrongly convert string typeThetoStringMethod, which is called first when forced to a numbervalueOf
  3. In the case of operational operators,valueOfPriority of is higher thantoString

[Symbol.toPrimitive]

MDN: Symbol.toPrimitive Is a built-in symbol value, which exists as a function value attribute of an object. When an object is converted to its original value, this function will be called.

Is it a little confused??? Just think of it as a function~~

  • Function: same asvalueOf()andtoString()It’s the same, butPriority should be given to both
  • When the function is called, a string parameter is passedhint, which represents the current operation mode. There are three modes:

    • String: string type
    • Number: number type
    • Default: default

Let’s take a look at the implementation

class A {
    constructor(count) {
        this.count = count
    }
    valueOf() {
        return 2
    }
    toString() {
        Return 'hahaha'
    }
    //I'm here
    [Symbol.toPrimitive](hint) {
        if (hint == "number") {
            return 10;
        }
        if (hint == "string") {
            return "Hello Libai";
        }
        return true;
    }
}

const a = new A(10)

console.log(`${a}`)     // 'Hello Libai' => (hint == "string")
console.log(String(a))  // 'Hello Libai' => (hint == "string")
console.log(+a)         // 10            => (hint == "number")
console.log(a * 20)     // 200           => (hint == "number")
console.log(a / 20)     // 0.5           => (hint == "number")
console.log(Number(a))  // 10            => (hint == "number")
console.log(a + '22')   // 'true22'      => (hint == "default")
console.log(a == 10)     // false        => (hint == "default")

The more special is the (+) splice, which belongs to thedefaultIt’s a new model.

Highlight: this method is not compatible with ie, so embarrassed that I don’t want to write it out~~

Analysis of interview questions

The following interview questions, which are required by big companies, are perfectly presentedtoStringAndvalueOfThe role of the government.

1. A = = 1 & & A = = 2 & & A = = 3 is true

Double equal sign (=): will triggerImplicit type conversion, so it can be usedvalueOfperhapstoStringTo achieve.

Every judgment will triggervalueOfMethods, and letvalue+1To make the next judgment true.

class A {
    constructor(value) {
        this.value = value;
    }
    valueOf() {
        return this.value++;
    }
}
const a = new A(1);
if (a == 1 && a == 2 && a == 3) {
    console.log("Hi Libai!");
}

Congruent (= = =): strictly equal to noImplicit transformation, used hereObject.definePropertyData hijacking

let value = 1;
Object.defineProperty(window, 'a', {
    get() {
        return value++
    }
})
if (a === 1 && a === 2 && a === 3) {
    console.log("Hi Libai!")
}

Above we are the whole situationwindowabovea, whenaIt’s triggered every time you make a judgmentgetAttribute to get the value, and each time to get the value will trigger a function to implement a self increment, judgment three times will be self increment three times, so the final formula will hold.

  • Note:definePropertyCan refer to this article to learn, click me to enter the portal
  • How to make the value of (a = = 1 & & A = = 2 & & A = = 3) true?

2. Realize an infinite accumulation function

Problem: using JS to realize an infinite accumulation functionaddExamples are as follows:

add(1); // 1
add(1)(2);  // 3
add(1)(2)(3); // 6
add(1)(2)(3)(4); // 10 

//And so on
function add(a) {
    Function sum (b) {// using closure
        A = B? A + B: a; // accumulation
        return sum;
     }
     sum.toString  =Function () {// is only called the last time
        return a;
    }
     Return sum; // returns a function
}

add(1)                // 1
add(1)(2)              // 3
add(1)(2)(3)         // 6
add(1)(2)(3)(4)         // 10
  • addFunction internal definitionsumFunction and return to realize continuous call
  • sumFunction to form a closure, each call to accumulate values, and then return the current functionsum
  • add()One function is returned each timesumUntil the last one is not called, it will be triggered by defaulttoStringMethod, so we rewrite it heretoStringMethod and returns the cumulative final valuea

Only in this way can we understand:

add(10): execute functionadd(10), backsumFunction, note that this time there is no callsum, default executionsum.toStringmethod. So output10

add(10)(20): execute functionadd(10), return sum (in this case, a is 10), and then executesum(20), at this timeA = 30, backsumLast callsum.toString()output30. Add (10) (20)… (n) and so on.

3. Realize multi parameter accumulation by Coriolis

Here is the above cumulative upgrade, to achieve multi parameter transfer accumulation.

add(1)(3,4)(3,5)    // 16
add(2)(2)(3,5)        // 12
function add(){
    //1 converts all parameters to an array
    let args = Array.prototype.slice.call(arguments)
    //2 call the add function again to pass and merge the current and previous parameters
    let fn = function() {
        let arg_fn = Array.prototype.slice.call(arguments)
        return add.apply(null, args.concat(arg_fn))
    }
    //Finally, it is called by default to return the merged value
    fn.toString = function() {
        return args.reduce(function(a, b) {
            return a + b
        })
    }
    return fn
}

//ES6 writing
function add () {
    let args = [...arguments];
    let fn = function(){
        return add.apply(null, args.concat([...arguments]))
    } 
    fn.toString = () => args.reduce((a, b) => a + b)
    return fn;
}

summary

If Xiaobai’s writing is not good, please give me a suggestionIf it helps you, please like it

More information sharing:

  • A programming ape who can’t write is not a good programming ape
  • A front-end learning notes based on vuepress, record, just for better fishing
  • Vue, nuxt server rendering, nodejs full stack project ~ perfect system for Xiaobai~

Recommended Today

Redis design and implementation 4: Dictionary Dict

In redis, the dictionary is the infrastructure. Redis database data, expiration time and hash type all take the dictionary as the underlying structure. Structure of dictionary Hashtable The implementation code of hash table is as follows:dict.h/dictht The dictionary of redis is implemented in the form of hash table. typedef struct dictht { //Hash table array, […]