Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand JavaScript type conversion

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces the relevant knowledge of "how to understand JavaScript type conversion". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Implement a function, and the operation result can satisfy the following expected results:

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

For a curious cutter, he can't help but give it a try. The first thing that comes to mind when seeing the topic is the use of higher-order functions and Array.prototype.reduce ().

Higher-order function (Higher-order function): a higher-order function means that it takes another function as an argument. In javascript, a function is a first-class citizen, allowing it to be passed as an argument or a return value.

The following solution is 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 it and found that it was wrong:

Add (1) (2) / / 3add (1,2) (3) / / 6add (1) (2) (3) / / Uncaught TypeError: add (...) (...) Is not a function (…)

The above solution is correct only in the case of add () (). When the chain operation has more than two or less than two parameters, the result cannot be returned.

And this is also a difficult point in this question, when add (), how to return both a value and a function for subsequent calls?

Later, after the guidance of a master, one of the solutions can be obtained by rewriting the valueOf method or toString method of the function:

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;}

Yeah? When I saw this solution, I was confused. Because I felt that fn.valueOf () had never been called from beginning to end, but verified the following result:

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

Amazing! that's right! Then the mystery must be in the above fn.valueOf = function () {}. Why is this the case? When is this method executed in the function? Just listen to me step by step.

ValueOf and toString

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

Object.prototype.valueOf ()

In MDN's words, the valueOf () method returns the original value of the specified object.

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

With the above sentence in mind, we will elaborate on what the so-called automatic invocation means.

Object.prototype.toString ()

The toString () method returns a string that represents the object.

Each object has a toString () method that is automatically called when the object is represented as a text value or when the object is referenced as a desired string.

Keep in mind here that valueOf () and toString () are called on their own in certain situations.

Original type

OK, let's pave the way. Let's first take a look at several primitive types of javascript. Excluding Object and Symbol, there are several primitive types:

Number

String

Boolean

Undefined

Null

When JavaScript makes comparisons or various operations, objects will be converted to these types for subsequent operations, as described below:

String type conversion

When an operation or operation requires a string and the object is not a string, the String conversion of the object is triggered, and an attempt to convert a non-string type to a String type is automatically made. The toString function is automatically called inside the system. For example:

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

Conversion rules:

If the toString method exists and returns the original type, the result of toString is returned.

If the toString method does not exist or does not return the original type, the valueOf method is called, and if the valueOf method exists and the original type data is returned, the result of the valueOf is returned.

In other cases, throw an error.

The above example is actually:

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

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

Suppose it is an array:

Var arr = [1Jue 2]; var str = '123' + arr;console.log (str); / / 1231 Jol 2

Above + arr, since this is a string addition operation, the subsequent arr needs to be converted to a string type, so + arr.toString () is actually called.

However, we can override the object's toString,valueOf method ourselves:

Var obj = {toString: function () {console.log ('called obj.toString'); return {};}, valueOf: function () {console.log (' called obj.valueOf') return '110 calls;}} alert (obj); / / called obj.toString// and called obj.valueOf// 110

Above alert (obj +'1'), obj will automatically call its own obj.toString () method to convert to the original type, if we do not rewrite its toString method, we will output [object Object] 1, here we rewrite toString and return an original type string 111, so the final alert comes out 1111.

The above conversion rule says that the toString method needs to exist and returns the original type, so if it does not return a primitive type, it will continue to look for the object's valueOf method:

Let's try to prove what happens if the toString () method is not available while an object is trying to convert to a string.

At this point, the system will call the valueOf () method again. Let's rewrite the toString and valueOf of the object:

Var obj = {toString: function () {console.log ('called obj.toString'); return {};}, valueOf: function () {console.log (' called obj.valueOf') return '110 calls;}} alert (obj); / / called obj.toString// and called obj.valueOf// 110

As you can see from the results, when toString is not available, the system tries the valueOf method again, if the valueOf method exists, and returns the data of the original type (String, Number, Boolean), and returns the result of valueOf.

What if neither toString nor valueOf returns primitive types? 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// and called obj.valueOf// Uncaught TypeError: Cannot convert object to primitive value

You can see that if both the toString and valueOf methods are not available, the system returns an error directly.

Added in 2017-03-07: after verifying the official ECMAScript5 documentation, it is found that there is something wrong with the above description. The conversion rules for converting Object types to String types are much more complicated than the above. The conversion rules are: 1. Set the original value to the result of calling ToPrimitive; 2. Returns ToString (original value). The rules for ToPrimitive and ToString can be found in the official document: ECMAScript5-ToString

Number type conversion

The conversion of String type is described above, and the conversion of Number type also occurs in many cases:

Call the Number () function to force Number type conversion

Calling a method of type Number is required for parameters such as Math.sqrt ()

Obj = = 1, when comparing

Obj + 1, when performing an operation

Similar to String type conversion, but the Number type is just the opposite, first query its own valueOf method, and then query its own toString method:

If valueOf exists and raw type data is returned, the result of valueOf is returned.

If toString exists and raw type data is returned, the result of toString is returned.

In other cases, throw an error.

Follow the steps above and try them separately:

Var obj = {valueOf: function () {console.log ('call valueOf'); return 5;}} console.log (obj + 1); / call valueOf// 6var obj = {valueOf: function () {console.log (' call valueOf'); return {};}, toString: function () {console.log ('call toString'); return 10;}} console.log (obj + 1) / / call valueOf// call toString// 11var obj = {valueOf: function () {console.log ('call valueOf'); return {};}, toString: function () {console.log (' call toString'); return {};}} console.log (obj + 1); / / call valueOf// to call toString// Uncaught TypeError: Cannot convert object to primitive valueBoolean transformation

When will the Boolean conversion take place:

Boolean comparison

When judging if (obj), while (obj), etc.

To put it simply, except that the following six values are converted to false, all of them are true:

Undefined

Null

-0

0 or + 0

NaN

"(empty string)

Boolean (undefined) / / falseBoolean (null) / / falseBoolean (0) / / falseBoolean (NaN) / / falseBoolean ('') / / falseFunction conversion

OK, back to the topic we started with, let's talk about the conversion of functions.

We define a function as follows:

Function test () {var a = 1bot console.log (1);}

What happens if we just call test instead of test ()?

As you can see, the test function we defined is reprinted here. In fact, the valueOf method of the function is called by itself:

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

Test.valueOf = function () {console.log ('call valueOf method'); return 2;} test;// output is as follows: / / call valueOf method / / 2

Similar to the Number transformation, if the valueOf method of a function does not return 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 toString method'); return 3;} test;// output is as follows: / / call valueOf method / / call toString method / / 3

Looking back at the answer to the question at the beginning of my text, I used the technique that the function will call the valueOf method itself, and rewrote the method. Let's 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 add is called once, the function fn is actually returned, and fn.valueOf () is actually returned.

Add (1); / / the output is as follows: / / enter add// to call valueOf// 1

In fact, it is equivalent to:

Reduce (function (a, b) {return a + b;}) / / 1

When chained twice:

Add (1) (2); / / the output is as follows: / / enter add// to call fn//, enter add// to call valueOf// 3

When chained three times:

Add (1) (2) (3); / / the 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 cycle. Only one call to valueOf is really called, and the previous operation is to merge parameters, recursively calling itself. Because * a call returns a fn function, the fn.valueOf of the function is finally called, and the reduce method is used to sum all the parameters.

In addition to overwriting the valueOf method, you can also overwrite the toString method, so, if you like, you can do the following:

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;}

There is a rule here that if only one of valueOf () or toString () is overwritten, the overwritten method will be called first, while if both are rewritten at the same time, the valueOf () method will be queried first, like the Number type conversion rule, and the toString () method will be queried if the valueOf () method returns a non-primitive type.

That's all for "how to understand JavaScript type conversion". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report