Implicit casts take a fairly smooth learning curve from basics to applications. The specific route is:
The primitive data types give rise to the concept of wrapper types ==> valueOf and toString methods ==> ToPrimitive abstract operations and [[DefaultValue]] operations ==> Rules for type conversions between various types ==> Common situations that cause implicit type conversions ==> Multiple example exercises to verify the usefulness of the method.
1. Start with basic packaging types
A discussion of basic wrapper types starts with an understanding of basic data types (also known as primitive types, simple data types, and so on). We then introduce the concept and role of the basic wrapper type through the behavior of the basic data type calling method.
1.1 Basic data types
It has been known that JavaScript has six basic data types: string, number, Boolean, NULL, undefined, and symbol.
Base types are neither objects nor methods to call. However, it is common to see primitive types of variables calling methods, such as:
let index = 'ABCDE'.indexOf('CD');
console.log(index); / / 2
Copy the code
In the above example, ‘ABCDE’ is the basic type of a string that calls indexOf directly, stores the return value of the method in the variable index, and prints it on the second line. You can see that this example works and the results are correct.
Since primitive types have no methods to call, why doesn’t the string ‘ABCDE’ get an error when calling indexOf? And it looks like indexOf was actually called, so who called it and returned the correct result? The answer is the basic packaging type. Let’s introduce basic packaging types.
1.2 Basic packaging types
Key words: package, basic package type, basic package type object
The previous section discussed that it’s not the string itself that calls the method, but the basic wrapper type. It’s time to talk more about basic packaging types.
In order for the basic type to call the method properly, the background automatically creates an object corresponding to the value of the basic type. This object is called the basic wrapper type, and then the method is called with this object. After the method is called, the object is destroyed. This process of generating a primitive wrapper type object from a primitive data type is called wrapping.
To put it simply, when a primitive type calls a method, the real caller of the method is not the primitive type we define directly, but the object we create behind the scenes for the primitive wrapper type. Also, this object is temporary, will not last forever, will be destroyed when used up.
Another feature of this object is that it corresponds to values of primitive types. However:
Not every basic type has a corresponding wrapper type
Four of the six basic types mentioned in the previous section have corresponding packaging types:
String (string) -> string, number(value) -> number, Boolean (Boolean) -> symbol(symbol) -> symbol
The symbol -> indicates the corresponding. Also: Note the capitalization of the first letter (the default for object names is capitalization).
Note: this article is for discussion onlyString, number, Boolean
Three basic types and their corresponding packaging types.
It is also important to understand that not only can the system implicitly create a wrapper object, but users can also manually and explicitly create an object of the basic wrapper type by using the keyword new and the corresponding wrapper type constructor, and passing in a value of the basic type, such as:
let n = new Number(22); // n is the wrapper object corresponding to the value 22
let str = new String('example'); // STR is the wrapper object for the string 'example'
let flag = new Boolean(false); // flag is the wrapper object corresponding to the Boolean value false
Copy the code
At this point, looking back at the example in section 1, you can again imagine the system creating a wrapper object in general:
let index = 'ABCDE'.indexOf('CD');
console.log(index); / / 2
Copy the code
You can see wrapper behavior in the background in the first line of code: the background wraps an object based on the string ‘ABCDE’. That is: When the indexOf method is called, a wrapper object is generated for a value of a primitive type that does not have a method to call (operation 1). The indexOf method is then called from this wrapper object (operation 2). The return value of the method is then assigned to the variable index. Finally, the wrapper object is destroyed (operation 3).
According to the above ideas, the corresponding code of the above process can be roughly simulated:
// step 1. Create an object of the basic wrapper type corresponding to 'ABCDE' :
let temp = new String('ABCDE');
// step 2. Call indexOf with the wrapper type temp and assign the return value to index:
let index = temp.indexOf('CD');
// step 3. Destroy the temp object
temp = null;
Copy the code
1.3 summarize
When a primitive datatype wants to call a method, a temporary wrapper object is generated for it, the method is called with this object, the result of the method execution is returned, and the temporary object is destroyed.
1.4 unpack the object box <-> unbox
In contrast to the process of generating a value of a primitive type, there is a process of generating a value of a primitive type from a wrapper object, called unbox. This process can be done either implicitly in the background or manually by calling the method valueOf.
The next section starts with the valueOf method and introduces another equally important method, toString.
2. Two important methods for objectsvalueOf
和 toString
2.1 Unbox for basic packaging typesvalueOf
methods
The unwrapping of the primitive wrapper type uses the valueOf function in the wrapper object, which converts an object to a valueOf the primitive type.
For Boolean, Number, and String primitives, a call to valueOf returns the valueOf the corresponding primitives:
let n = new Number(22); // The basic value of the package is 22
// The unwrapped result is the value of the corresponding base data type
console.log(n.valueOf() === 22); // true
let str = new String('example'); // Wrap basic string data 'example'
// The unwrapped result is the value of the corresponding base data type
console.log(str.valueOf() === 'example'); // true,
let flag = new Boolean(false); // Wrap basic Boolean data false
// The unwrapped result is the value of the corresponding base data type
console.log(flag.valueOf() === false); // true
Copy the code
Sometimes implicit unwrapping occurs in the background, where valueOf methods are called on objects of wrapper type, for example:
let a = new Number(1);
let b = a + 1; Let b = a.valueof () + 1;
console.log(b); / / to 2 b
console.log(typeof a); // object
console.log(typeof b); // number, the type of b is the basic data type, not the wrapper type
Copy the code
Even a line of code can be wrapped and unwrapped, for example:
let num = 3.14159;
console.log(num.valueOf()); / / 3.14159
Copy the code
In the second line of the above block, the variable num calls the function valueOf. In this case, num is first wrapped as an object of basic wrapper type, and this object is wrapped when the valueOf method is called.
2.2 Of other objectsvalueOf
methods
The valueOf method is not the only one for basic wrapper types. Many JavaScript build-in objects have this function, and most objects override this method to make the result of execution match the object itself. Let’s look at how the valueOf methods of some other objects behave.
The following lists the return values of the valueOf method for common built-in objects:
object | The return value |
---|---|
Boolean, Number and String | Values corresponding to each base type |
Array, Function, Object | In its own right |
Date | The number of milliseconds between the current time and midnight 1970.01.01 |
Math and Error | There is no valueOf method |
Here are the results:
// Array calls valueOf, which returns the array itself
let array = [1.'hello'.false];
console.log(array.valueOf() === array); // true
// The function calls valueOf, which returns the function itself
function foo(){}
console.log(foo.valueOf() === foo); // true
// The object calls valueOf, which returns the object itself
let obj = {
name: 'doug'.age : 22
};
console.log(obj.valueOf() === obj); // true
// The number of milliseconds between the current time and midnight, January 1, 1970
console.log(new Date().valueOf()); / / 1551684737052
Copy the code
Conclusion: The valueOf method can convert an object to a primitive data type. Not every object has this method (e.g., Math and Error objects). Call this function to return the value of the corresponding primitive type for Boolean, numeric, and string primitives. Object returns itself when it calls this function (arrays and functions return themselves, since they are also objects by nature).
The valueOf method brings to mind another important method for type conversions, toString, which is discussed in the next section.
2.3 Methods by which objects can be represented as stringstoString()
Every built-in Object has this method, which is inherited from Object. Most built-in objects override this function to make the result of execution match the object itself. A common object call to the toString method returns the following:
-
For user-created objects, return ‘[Object object]’. (There is an exception, see last section)
-
For Math objects, return “[object Math]”:
// A custom object
console.log({name: 'doug'}.toString()); // '[object Object]'
/ / Math object
console.log(Math.toString()); // '[object Math]'
Copy the code
- For objects of the three basic wrapper types mentioned in Part 1:
- For Boolean objects, the string “true” or “false” is returned, depending on the value of its corresponding base data type.
- For numeric objects, returns the string representation of the number in the specified base, which is 10.
- For string objects, return the string (and call) corresponding to the base data type
valueOf
The method gives the same result.
// Boolean wrapper type object
console.log(new Boolean(false).toString()); // 'false'
// Numeric wrap the object of type object
console.log(new Number(3.14159).toString()); / / '3.14159'
// String wraps an object of type object
console.log(new String('str').toString()); // 'str'
Copy the code
- For arrays, return a string of all items, concatenated with a comma.
/ / array
console.log([1.'hello'.false].toString()); // '1,hello,false'
Copy the code
- For functions, the toString method returns a string containing the source text used to define the function.
/ / function
function foo(){console.log('hello foo'); }console.log(foo.toString());
// 'function foo(){console.log('hello foo'); } '
Copy the code
- Other objects
- For the RegExp object, return the string of the regular expression.
- For Date objects, return a string representing a specific time.
- For Error objects, return a string containing the contents of the Error.
// Regular objects
console.log(new RegExp("a+b+c").toString()); // "/a+b+c/"
// Date object
console.log(new Date().toString());
// Mon Mar 04 2019 17:07:54 GMT+0800
/ / the Error object
console.log(new Error('fatal error').toString());
// 'Error: fatal error'
Copy the code
Not every Object has a toString() method. For example, an Object created by passing a null argument to object.create has no toString or valueOf methods because its prototype is null
2.4 summarize
The Japanese section discusses two important functions, valueOf, which returns a valueOf the caller’s primitive type, and toString, which can turn an object into a string.
These two functions will play an important role in the casting process.
Note: There are other names for packaging and unpackaging processes, such as wrap and unwrap, which are just different words for the same process.