Thinking about the conversion of JavaScript type caused by a question in a face

Source: Internet
Author: User
Tags object object

recently, someone in the group sent the following question:
To implement a function, the result of the operation can meet the following expected Results:

Add (1) (2)//3add (1, 2, 3) (ten)//16add (1) (2) (3) (4) (5)//15

For a curious transduction, can't help but try, see the first thought of the topic is the use of Higher-order functions and Array.prototype.reduce() .

Higher-order functions (higher-order function): The High-order function means that it receives another function as an argument. In javascript, a function is a class citizen, allowing a function to be passed as a parameter or a return Value.

The following solution was Obtained:

function add () {    var args = Array.prototype.slice.call (arguments);    return function () {        var arg2 = Array.prototype.slice.call (arguments);        Return args.concat (arg2). reduce (function (a, b) {            return a + b;        });}    }

verified, and found the wrong:

Add (1) (2)//3add (1, 2) (3)//6add (1) (2) (3)//uncaught typeerror:add (...) (...) is not a function (...)

The solution above add()() is correct only under the Circumstances. The result cannot be returned when the chained operation has more than two parameters or less than two.

And this is also a difficult point of the problem, add() when, How to return a value and return a function for subsequent continuation of the call?

Later through the expert pointing, by rewriting the function of the valueOf method or toString method, you can get one of the solutions:

function Add () {var args = Array.prototype.slice.call (arguments); var fn = function () {var arg_fn = Array.prototype.slice . Call (arguments); return add.apply (null, args.concat (arg_fn));} fn.valueof = function () {return args.reduce (function (a, b) {return A + b;})} Return fn;}

Well? The first time I saw this solution, I was crazy. Because I feel like I fn.valueOf() haven't been called from beginning to end, but I've verified the result:

Add (1)//1add (3)//6add (1) (2) (3) (4) (5)//15

The Magic is right! Then the mystery must be in the top of the fn.valueOf = function() {} Inside. Why is it so? How is this method executed at the time of the function? And listen to me step by Step.

valueOf and ToString

Let's take a quick look at these two methods:

Object.prototype.valueOf ()

In the case of MDN, the ValueOf () method returns the original value of the specified Object.

JavaScript calls the ValueOf () method to convert an object to a value of the original type (numeric, string, and Boolean values). But we seldom need to call this function ourselves, and the ValueOf method is usually called automatically by JavaScript.

Remembering the above sentence, we will dwell on what the so-called automatic call Means.

Object.prototype.toString ()

The ToString () method returns a String representing the Object.

Each object has a toString () method, which is called automatically when the object is represented as a literal value or when an object is referenced in the way it expects a string.

First of all, remember that valueOf () and toString () are invoked on their own in certain situations.

Original Type

All right, Let's go. learn about some of the primitive types of javascript, except Object and Symbol, with the following primitive types:

    • Number
    • String
    • Boolean
    • Undefined
    • Null

The object is converted to these types when the JavaScript is compared or various operations are performed, and the following actions are Followed:

String type Conversion

A string conversion of Object is triggered when an action or operation is required, for example:

var obj = {name: ' Coco '};var str = ' 123 ' + obj;console.log (str);  123[object object]

Conversion Rules:

    1. toStringreturns the result if the method exists and returns toString the original Type.
    2. If the method toString does not exist or returns a "primitive type," the method is called, valueOf if the valueOf method exists and returns the "raw type" data, valueOf the returned Result.
    3. Other cases, throw an Error.

The above example is actually:

var obj = {name: ' Coco '};var str = ' 123 ' + obj.tostring ();

Where obj.toString() the value is "[object Object]" .

The assumption is an array:

var arr = [1, 2];var str = ' 123 ' + Arr;console.log (str); 1231,2

+ arrthe above is actually called + arr.toString() .

however, we can rewrite the object by ourselves toString , by valueOf :

var obj = {    tostring:function () {        console.log (' called obj.tostring ');        Return ' 111 ';}    } Alert (obj);//call the obj.tostring//111

Above alert(obj) , obj will automatically call its own obj.toString() method into the original type, if we do not rewrite its toString method, will output [object Object] , here we rewrite toString , and return a primitive type string 111 , so the final alert out of 11 1.

The above conversion rules are written, the toString method needs to exist and return the original type, then if the return is not a primitive type, then will continue to find the Object's valueOf method:

Here we try to prove that if toString() the method is not available, the system calls the valueOf() method, and we rewrite the object as follows valueOf :

var obj = {    tostring:function () {        console.log (' called obj.tostring ');        return {};    },    valueof:function () {        console.log (' call obj.valueof ')        return ';    }} Alert (obj);//called obj.tostring//called obj.valueof//110

As you can see from the results, when toString unavailable, the system tries the valueOf method again, if the valueOf method exists, and returns the original type (String, number, Boolean) data, valueOf the returned Result.

So what if, toString and valueOf The return is not the original type? Look at the following example:

var obj = {    tostring:function () {        console.log (' called obj.tostring ');        return {};    },    valueof:function () {        console.log (' called obj.valueof ')        return {};}    } Alert (obj);//called obj.tostring//called obj.valueof//uncaught typeerror:cannot Convert object to primitive value

It can be found that if toString valueOf the and method are not available, the system will return an error directly.

number type Conversion

The above describes the conversion of a String type, and many times a conversion of type number is also occurring:

    • Call the number () function to force number type conversion
    • Calling the Math.sqrt () parameter requires a method of type number
    • obj == 1, when compared to the
    • obj + 1, when the operation is performed

Similar to String type conversions, But the number type is just the reverse, first querying its own valueOf method, and then querying its own toString method:

    1. valueOfreturns the result if it exists and returns the raw type data valueOf .
    2. toStringreturns the result if it exists and returns the raw type data toString .
    3. Other cases, throw an Error.

Follow these steps to try each of the Following:

var obj = {    valueof:function () {        console.log (' call valueOf ');        return 5;}    } Console.log (obj + 1); Call VALUEOF//6
var obj = {    valueof:function () {        console.log (' call valueOf ');        return {};    },    tostring:function () {        console.log (' call toString ');        return ten;}    } Console.log (obj + 1); Call Valueof//call TOSTRING//11
var obj = {    valueof:function () {        console.log (' call valueOf ');        return {};    },    tostring:function () {        console.log (' call toString ');        return {};    }} Console.log (obj + 1); Call Valueof//call tostring//uncaught Typeerror:cannot convert object to primitive value

  

Boolean Conversion

When does a Boolean conversion occur:

    • When comparing Boolean
    • If (obj), while (obj) judgment

Simply put, all others are true except for the following 6 value conversion results are false:

    • Undefined
    • Null
    • -0
    • 0 or +0
    • NaN
    • "(empty String)
Boolean (undefined)//falseboolean (null)//falseboolean (0)//falseboolean (NaN)//falseboolean (")//false

 

Function Conversion

well, at the end of the day we go back to the beginning of the topic, talking about the transformation of Functions.

We define a function as Follows:

function Test () {    var a = 1;    Console.log (1);}

What if we just call test instead test() , and see what happens?

As you can see, here we re-print our definition of the test function, in fact, the method of invoking the function itself valueOf :

Let's rewrite the method of the test function valueOf .

test.valueof = function () {    console.log (' Call valueOf method ');    Return 2;} The test;//output is as Follows://call valueOf METHOD//2

Similar to the number conversion, if a Function's valueOf method returns a primitive type, it continues to find its toString method:

test.valueof = function () {    console.log (' Call valueOf method ');    Return {};} test.tostring= function () {    console.log (' Call the ToString method ');    Return 3;} The test;//output is as Follows://call the valueOf method//call the toString METHOD//3

essay

Look back at the beginning of my text the answer to the question, it is the use of the function will call valueOf the method itself, and rewrite the Method. We make a slight change and the deformation is as follows:

function add () {console.log (' enter add '); var args = Array.prototype.slice.call (arguments); var fn = function () {var ARG_FN = Array.prototype.slice.call (arguments); console.log (' call fn '); return add.apply (null, args.concat (arg_fn));} fn.valueof = function () {console.log (' call valueOf '); return args.reduce (function (a, b) {return A + b;})} Return fn;}

When an add is called, the actual function is to return the fn, which is actually the return fn.valueOf() ;

Add (1);//output is as Follows://enter add//call VALUEOF//1

is actually equivalent to:

[1].reduce (function (a, B) {    return a + B;}) 1

When chaining calls two times:

Add (1) (2);//output is as Follows://enter add//call fn//enter add//call VALUEOF//3

When chaining calls three times:

Add (1) (2) (3);//output is as Follows://enter add//call fn//enter add//call fn//enter add//call VALUEOF//6

As you can see, there is actually a loop here. Only the last call is actually called valueOf , and the previous operation is the merge parameter, recursive call itself, because the last call returned an FN function, so the function was eventually called fn.valueOf , and the reduce method was used to sum all Parameters.

In addition to rewriting the method, you valueOf can also rewrite toString the method, so if you like, the following can Also:

function Add () {var args = Array.prototype.slice.call (arguments); var fn = function () {var arg_fn = Array.prototype.slice . Call (arguments); return add.apply (null, args.concat (arg_fn));} fn.tostring = function () {return args.reduce (function (a, b) {return A + b;})} Return fn;}

Here is a rule, if only rewrite valueOf() or one toString() , will first call the overridden method, and if two simultaneous rewrite, it will be like a String conversion rule, the first query valueOf() method, in the valueOf() case of non-primitive type returned by the method of the query toString() party Method.

If you can read it carefully, I believe it will be fruitful.

To this end of this article, if there are any questions or suggestions, you can communicate a lot, original articles, writing limited, caishuxueqian, If there is not in the text, million hope to Inform.

Thinking about the conversion of JavaScript type caused by a question in a face

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.