In general, casts take place at compile time in statically typed languages, while casts take place at run time in dynamically typed languages, though in JavaScript they are often called casts. In fact, I think it’s more accurate to divide it into “explicit casting” and “implicit casting”.
The data type
There are six simple data types in the JS, undefined, null, string, number, symbol, and a type of complex object, but when the JavaScript in the statement only one type, only to run during will determine the current type, at run time, Because JavaScript is a weakly typed language, there are no strict restrictions on types, so that operations can be performed between different types, which involves converting between types.
Displays casts
A display conversion is a manual conversion from one value to another, and is a conversion that code has an explicit intent for. Boolean(),String(), and Number() are used to convert a value to a Number,String(), or Boolean(). ToString(),ToBoolean(); ToNumber(); ToString(); ToBoolean();
In addition to the Number(),String(), and Boolean() functions, the following methods also display conversions.
Refer to the official ECMA documentation
1. toString()
ToString handles non-string coercion as follows:
// Number to string
(123).toString() / / '123'
// Boolean to string
(true).toString() // 'true'
// Array to string
['hello'.'world'].toString() // 'hello,world'
// Object to string
({name: 'hello world'}).toString() // '[object Object]'
// Date object to string
Date().toString() // 'Sat Aug 08 2020 01:26:31 GMT+0800 '
//JSON object to string
JSON.toString() // '[object JSON]'
// Function turns to a string
Function.toString() // 'function Function() { [native code] }'
// Function to string
(function(){ return 1; }).toString() // 'function () { return 1; } '
Copy the code
Ordinary objects, invoke is internal toPrimirive method, unless its own definition, or with the Object. The prototype. The toString () returns the value of [[class]] internal attributes, such as [Object Object].
2.toNumber
Other rules for converting to number are shown in the table below:Rule for converting String to Number:
- (1) If the string contains numbers so long convert to a number of pairs
- (2) If the string contains a hexadecimal format, convert to a decimal number
- (3) If the string is empty, then it is converted to 0
- (4) If the string contains characters other than the above, then it is converted to NaN.
3.toBoolean
ToBoolean conversion rules are as follows:
As can be seen above, all objects return true, including [] and {}. But there’s a problem with falsy objects.
var a = new Boolean(false) //false
var b = new Number(0) //false
var c = new String(' ') //false
Boolean(a && b && c) //true Note that this must be wrapped in Boolean
Copy the code
So false returns true when encapsulated.
4. Unary operator (+ -)
+ and -0 explicitly convert non-numbers to numbers.
console.log(+ '1.02'); / / 1.02
console.log(+ -0); / / - 0
console.log(+ []); / / 0
console.log(+ {}); //NaN
console.log({} -0); //NaN
Copy the code
5.parseInt()
ParseInt () is often used when dealing with integers. When converting a string, the parseInt() function ignores the space before the string until it finds the first non-space character.
ParseInt () returns NaN if the first character is not a number or a minus sign, as does parseInt() converting an empty string.
If the first character is a numeric character, parseInt() continues parsing the second character until all strings are parsed or a non-numeric character is encountered, returning only the numeric part.
The parseInt() method also has a base mode that converts binary, octal, hexadecimal, or any other base string into integers.
The base is specified by the second argument to the parseInt() method, so to parse the hexadecimal value, of course, you can call the parseInt() method this way for binary, octal, or even decimal (the default mode).
If the second argument is 0, undefined, or null, it is ignored.
console.log( parseInt(' -88ddd2 '));/ / - 88
console.log(parseInt("100".2)); / / 4
console.log(parseInt("AF")); //NaN
console.log(parseInt("AF".16)); / / 175
console.log(parseInt("AG".16)); // convert only hexadecimal parts
console.log(parseInt("1.23")); // 1 converts 1.23 to a string first
console.log(( parseInt('90'.undefined)));/ / 90
Copy the code
6.parseFloat
Like the parseInt() function, parseFloat() parses each character from the first character (position 0). Parse to the end of the string or until an invalid floating-point numeric character is encountered.
That is, the first decimal point in the string is valid, but the second decimal point is invalid, and the string after it is ignored.
But parseFloat() only parses decimal, so it doesn’t need to specify a second argument as the base.
ParseFloat () returns an integer if the string contains a number that can be parsed to a positive number (no decimal point, or zero after the decimal point).
console.log(parseFloat('123AF')); / / 123 console. The log (parseFloat (" 22.3.56 ")); / / 22.3 console. The log (parseFloat (" 04.900 ")); / / 4.9Copy the code
The difference between parseInt() and parseFloat() is:
- The first decimal point in the string parsed by parseFloat() is valid, whereas parseInt() stops parsing when it encounters a decimal point, because a decimal point is not a valid numeric character.
- ParseFloat () always ignores leading zeros, hexadecimal strings are always converted to 0, and the second argument to -parseint () sets the base to convert to.
Implicit cast
Implicit conversions are usually the case when operators are involved, such as adding two variables, or comparing whether two variables are equal. Implicit type conversions are already shown in our example above. ToPrimitive’s rules are also followed for converting objects ToPrimitive types, as discussed below.
1. Type conversion from the ES specification
ToPrimitive
When an object is converted to its original type, the built-in ToPrimitive method is called, which in turn calls the OrdinaryToPrimitive method.
The ToPrimitive method takes two parameters, the input value and the PreferredType of the desired conversion.
- If it doesn’t come in
PreferredType
Argument to make hint equal to “default” - if
PreferredType
“Hint String”, “hint” equals “String” - if
PreferredType
Hint Number, so hint equals “Number” - let
exoticToPrim
Is equal to theGetMethod(input, @@toPrimitive)
, which means to get parametersinput
的@@toPrimitive
methods - if
exoticToPrim
Instead of Undefined, let result equal toCall(exoticToPrim, input, « hint »)
ExoticToPrim (hint) returns result if result is the original data type, otherwise throws an exception of the wrong type - If hint is “default”, make hint equal to “number”
- Returns the result of the OrdinaryToPrimitive(input, hint) abstraction operation
OrdinaryToPrimitive
The OrdinaryToPrimitive method also takes two parameters, O, the input value, and hint, the type to be converted.
(1) If the input value is an object
(2) If hint is a string and the value is ‘string’ or ‘number’
(3) If hint is ‘string’, set methodNames to toString, valueOf
(4) If hint is ‘number’, set methodNames to valueOf, toString
Set method to O[name] (valueOf and toString)
(6) If method can be called, set result equal to the result of method execution, return result if result is not an object, or raise a type error.
ToPrimitive code implementation
If you only use words to describe it, you will feel too obscure, so I will use my own code to implement these two methods to help you understand.
// Get the type
const getType = (obj) = > {
return Object.prototype.toString.call(obj).slice(8, -1);
}
// Whether it is a primitive type
const isPrimitive = (obj) = > {
const types = ['String'.'Undefined'.'Null'.'Boolean'.'Number'];
returntypes.indexOf(getType(obj)) ! = = -1;
}
const ToPrimitive = (input, preferredType) = > {
// If input is a primitive type, no conversion is required
if (isPrimitive(input)) {
return input;
}
let hint = ' ',
exoticToPrim = null,
methodNames = [];
// Hint defaults to "default" when the optional preferredType parameter is not provided;
if(! preferredType) { hint ='default'
} else if (preferredType === 'string') {
hint = 'string'
} else if (preferredType === 'number') {
hint = 'number'
}
exoticToPrim = input.@@toPrimitive;
// If there is toPrimitive method
if (exoticToPrim) {
// If exoticToPrim returns a primitive type after execution
if (typeof(result = exoticToPrim.call(O, hint)) ! = ='object') {
return result;
// If exoticToPrim returns an object
} else {
throw new TypeError('TypeError exception')}}Here the default hint value is given as number. Symbol and Date change the default value by defining the @@toprimitive method
if (hint === 'default') {
hint = 'number'
}
return OrdinaryToPrimitive(input, hint)
}
const OrdinaryToPrimitive = (O, hint) = > {
let methodNames = null,
result = null;
if (typeofO ! = ='object') {
return;
}
// This determines whether toString or valueOf is called first
if (hint === 'string') {
methodNames = [input.toString, input.valueOf]
} else {
methodNames = [input.valueOf, input.toString]
}
for (let name in methodNames) {
if (O[name]) {
result = O[name]()
if (typeofresult ! = ='object') {
return result
}
}
}
throw new TypeError('TypeError exception')}Copy the code
To summarize, when performing a type conversion, you usually convert a reference type to a primitive type using the ToPrimitive method. If the @@Toprimitive method has a reference type, the @@Toprimitive method is called, and the original type is returned. If it is still an object, an error is thrown.
If there is no toPrimitive method on the object, the toString or valueOf method is called first based on the target type of the conversion, and returns the valueOf the original type if either method is returned. Otherwise, an error will be thrown.
Symbol.toPrimitive
After ES6, the symbol.toprimitive method is provided, which has the highest precedence when converting types.
const obj = {
toString() {
return '1111'
},
valueOf() {
return 222},Symbol.toPrimitive]() {
return Awesome!}}const num = 1 + obj; / / 667
const str = '1' + obj; / / '1666'
Copy the code
Summary type conversion has been learning JS is difficult to understand a concept, because conversion rules are more complex, often make people feel puzzling. But if you understand how these transformation rules work from the ECMA specification, it’s easy to see why you end up with those results.
Reference: juejin. Cn/post / 684490…
https://zhuanlan.zhihu.com/p/85731460
Copy the code