Number
, String
, Boolean
, Null
, Undefined
. The Symbol
type has been added to this list in ES6, which behaves not at all like other types. Explicit type conversion is a simple and straightforward process, but everything changes when it comes to implicit type conversion. Here, what happens in JavaScript, some consider strange or illogical, although, of course, if you look into the standards, it becomes clear that all these "oddities" are features of the language. Anyway, any JS-developer periodically has to deal with implicit type conversion, besides, tricky questions about type casting may well meet at the interview. true + false 12 / "6" "number" + 15 + 3 15 + 3 + "number" [1] > null "foo" + + "bar" 'true' == true false == 'false' null == '' !!"false" == !!"true" ['x'] == 'x' [] + null + 1 0 || "0" && {} [1,2,3] == [1,2,3] {}+[]+{}+[1] !+[]+[]+![] new Date(0) - 0 new Date(0) + 0
==
, when comparing values of different types. The implicit type conversion performed by the ==
operator makes this table much less comprehensible and logical than, say, a table for the strict equality operator, ===
, a link to which can be found on the above page. To memorize the comparison table for the operator ==
almost impossible. But remembering all this is not necessary - it is enough to master the principles of type conversion used in JavaScript.Number(value)
, this is called explicit type conversion (or explicit type conversion).1 == null
, 2/'5'
, null + new Date()
. An implicit type conversion can also be triggered by an expression context, such as if (value) {…}
, where value
implicitly cast to a logical data type.===
. The non-strict equality operator, ==
, on the other hand, performs the comparison operation and, if necessary, performs implicit type conversion.String
)Boolean
Number
String()
function. An implicit conversion causes the use of the usual addition operator, +
, with two operands, if one of them is a string: String(123) // 123 + '' //
String(123) // '123' String(-12.3) // '-12.3' String(null) // 'null' String(undefined) // 'undefined' String(true) // 'true' String(false) // 'false'
Symbol
type, the case is somewhat more complicated, since values of this type can be converted to a string type only explicitly. Here you can read the details about the conversion rules of type Symbol. String(Symbol('my symbol')) // 'Symbol(my symbol)' '' + Symbol('my symbol') // TypeError
Boolean()
function. An implicit conversion occurs in a logical context, or is called by logical operators ( ||
&&
!
). Boolean(2) // if (2) { ... } // !!2 // 2 || 'hello' //
||
and &&
convert values to a logical type for internal purposes, and return the values of the source operands, even if they are not logical. // 123, true // 'hello' 123 && let x = 'hello' && 123; // x === 123
true
or false
, it is easiest to master this kind of conversion, remembering the expressions that return false
: Boolean('') // false Boolean(0) // false Boolean(-0) // false Boolean(NaN) // false Boolean(null) // false Boolean(undefined) // false Boolean(false) // false
true
, including objects, functions, arrays, dates, and user-defined types. Values of type Symbol
also converted to true
. Empty objects and empty arrays are also converted to true
: Boolean({}) // true Boolean([]) // true Boolean(Symbol()) // true !!Symbol() // true Boolean(function() {}) // true
Number()
function - that is, according to the same principle used for the Boolean
and String
types.Number
type is performed by the following operators:>
, <
, <=
, >=
).|
, &
, ^
, ~
).-
, +
, *
, /
, %
). Note that the +
operator with two operands does not cause an implicit conversion to a numeric type if at least one operator is a string.+
.==
(and also !=
). Note that the ==
operator does not perform an implicit conversion to a number if both operands are strings. Number('123') // +'123' // 123 != '456' // 4 > '5' // 5/null // true | 0 //
Number(null) // 0 Number(undefined) // NaN Number(true) // 1 Number(false) // 0 Number(" 12 ") // 12 Number("-12.34") // -12.34 Number("\n") // 0 Number(" 12s ") // NaN Number(123) // 123
\n
and \t
characters at the beginning or end of the string, and returns NaN
if the resulting string is not a real number. If the string is empty, 0 is returned.null
and undefined
handled differently: null
converted to 0
, while undefined
converted to NaN
.Symbol
cannot be converted to a number, either explicitly or implicitly. Moreover, when attempting such a conversion, a TypeError
error is TypeError
. One would expect that this would cause the conversion of a Symbol
value to NaN
, as it does with undefined
, but it does not. Details on the rules for converting Symbol
type values can be found at MDN . Number(Symbol('my symbol')) // TypeError +Symbol('123') // TypeError
==
operator to null
or undefined
conversion to a number is performed. The value null
is only null
or undefined
and is not equal to anything else. null == 0 // false, null 0 null == null // true undefined == undefined // true null == undefined // true
NaN
not equal to anything, including yourself. In the following example, if the value is not equal to itself, then we are dealing with NaN
if (value !== value) { console.log("we're dealing with NaN here") }
[1] + [2,3]
, it first needs to convert the object to a primitive value, which is then converted to its final type. When working with objects, we recall, there are also only three directions of transformations: to a number, to a string, and to a logical value.true
, this is also true for empty objects and arrays.[[ToPrimitive]]
internal method, which is responsible for both the conversion to a numeric type and the conversion to a string.[[ToPrimitive]]
method: function ToPrimitive(input, preferredType){ switch (preferredType){ case Number: return toNumber(input); break; case String: return toString(input); break default: return toNumber(input); } function isPrimitive(value){ return value !== Object(value); } function toString(){ if (isPrimitive(input.toString())) return input.toString(); if (isPrimitive(input.valueOf())) return input.valueOf(); throw new TypeError(); } function toNumber(){ if (isPrimitive(input.valueOf())) return input.valueOf(); if (isPrimitive(input.toString())) return input.toString(); throw new TypeError(); } }
[[ToPrimitive]]
passed an input value and the preferred type to convert it to: Number
or String
. The preferredType
argument is optional.[[ToPrimitive]]
: this is valueOf
and toString
. Both methods are declared in the Object.prototype
, and are thus available for any type based on Object
, for example - Date
, Array
, and so on.input.toString()
, if the result is a value of the primitive type - return it.input.valueOf()
, if the result is a value of a primitive type - return it.input.toString()
nor input.valueOf()
gives a primitive value, give a TypeError error.valueOf
(3) is first called, if the result cannot be obtained, toString
(2) is called. When converting to a string, the reverse sequence of actions is used — first toString
(2) is called, and in case of failure, valueOf
(3) is called.valueOf
method, or have a valueOf
, which is returned by the object for which it is called ( this
), so this value is ignored, since it is not a primitive. That is why converting to numbers and strings can work the same way - both come down to the toString()
call.preferredType
parameter. But there are two exceptions: the lax equality operator ==
and the +
operator with two operands cause a default conversion (the preferredType
not specified or is set to default
). In this case, most of the built-in types are considered, as a standard behavior, conversion to a number, with the exception of the Date
type, which converts an object into a string.Date
behavior on type conversion: let d = new Date(); // let str = d.toString(); // 'Wed Jan 17 2018 16:15:42' // , - Unix let num = d.valueOf(); // 1516198542525 // // true d console.log(d == str); // true // // false, d valueOf() console.log(d == num); // false // 'Wed Jan 17 2018 16:15:42Wed Jan 17 2018 16:15:42' // '+', , '==', console.log(d + d); // 0, '-' , console.log(d - d);
toString()
and valueOf()
can be redefined to intervene in the logic of converting an object into primitive values. var obj = { prop: 101, toString(){ return 'Prop: ' + this.prop; }, valueOf() { return this.prop; } }; console.log(String(obj)); // 'Prop: 101' console.log(obj + '') // '101' console.log(+obj); // 101 console.log(obj > 100); // true
obj + ''
returns '101'
as a string. The +
operator calls the standard transform mode. As already mentioned, Object
treats coercion to a number as a default conversion, so it uses the valueOf()
method first and not the toString()
method.toString
and valueOf
methods.[[ToPrimitive]]
by implementing the object method [Symbol.toPrimtive]
. class Disk { constructor(capacity){ this.capacity = capacity; } [Symbol.toPrimitive](hint){ switch (hint) { case 'string': return 'Capacity: ' + this.capacity + ' bytes'; case 'number': // KiB return this.capacity / 1024; default: // return this.capacity / 1024; } } } // 1MiB let disk = new Disk(1024 * 1024); console.log(String(disk)) // Capacity: 1048576 bytes console.log(disk + '') // '1024' console.log(+disk); // 1024 console.log(disk > 1000); // true
true + false // 1 12 / "6" // 2 "number" + 15 + 3 // 'number153' 15 + 3 + "number" // '18number' [1] > null // true "foo" + + "bar" // 'fooNaN' 'true' == true // false false == 'false' // false null == '' // false !!"false" == !!"true" // true ['x'] == 'x' // true [] + null + 1 // 'null1' 0 || "0" && {} // {} [1,2,3] == [1,2,3] // false {}+[]+{}+[1] // '0[object Object]1' !+[]+[]+![] // 'truefalse' new Date(0) - 0 // 0 new Date(0) + 0 // 'Thu Jan 01 1970 02:00:00(EET)0'
+
operator with two operands causes a conversion to a number for true
and false
: true + false ==> 1 + 0 ==> 1
/
, causes a conversion to a number for the string '6'
: 12 / '6' ==> 12 / 6 ==>> 2
+
operator has left-to-right associativity, so the expression "number" + 15
is executed first. Since one of the operands is a string, the +
operator causes a conversion to the string for the number 15
. In the second step, the evaluation of the expression "number15" + 3
processed in the same way: "number" + 15 + 3 ==> "number15" + 3 ==> "number153"
15 + 3
expression is evaluated first. There is absolutely no need for type conversion, since both operands are numbers. In the second step, the value of the expression 18 + 'number'
calculated, and since one of the operands is a string, a conversion to the string is called. 15 + 3 + "number" ==> 18 + "number" ==> "18number"
>
performs numeric comparison [1]
and null
: [1] > null ==> '1' > 0 ==> 1 > 0 ==> true
+
operator has a higher priority than the normal +
operator. As a result, the expression +'bar'
evaluated first. Unary +
invokes a conversion to a number for the string 'bar'
. Since the string is not a valid number, the result is NaN
. In the second step, the value of the expression 'foo' + NaN
calculated. "foo" + + "bar" ==> "foo" + (+"bar") ==> "foo" + NaN ==> "fooNaN"
==
operator causes the conversion to a number, the string 'true'
converted to NaN
, the Boolean value true
converted to 1
. 'true' == true ==> NaN == 1 ==> false false == 'false' ==> 0 == NaN ==> false
==
operator usually converts to a number, but this is not the case with the value null
. The value null
is only null
or undefined
and nothing else. null == '' ==> false
!!
converts the strings 'true'
and 'false'
to boolean true
, since they are non-empty strings. Then the ==
operator simply checks the equality of the two logical values true
without type conversion. !!"false" == !!"true" ==> true == true ==> true
==
operator calls a conversion to a numeric type for arrays. The object method Array.valueOf()
returns the array itself, and this value is ignored because it is not a primitive. The array method toString()
converts the array ['x']
into the string 'x'
. ['x'] == 'x' ==> 'x' == 'x' ==> true
+
operator causes conversion to a number for the empty array []
. The method of the Array
object valueOf()
ignored, since it returns the array itself, which is not a primitive. The array method toString()
returns an empty string.'' + null + 1
calculated. [] + null + 1 ==> '' + null + 1 ==> 'null' + 1 ==> 'null1'
||
and &&
in the course of operation, cast the operands to a logical type, but return the source operands (which are of a different type than the logical one). The value 0
false, and the value '0'
true, since it is a non-empty string. An empty object {}
is also converted to a true value. 0 || "0" && {} ==> (0 || "0") && {} ==> (false || true) && true // ==> "0" && {} ==> true && true // ==> {}
==
operator checks for equality of references to objects (and not whether objects contain the same values) and two arrays are two different objects, false
will be returned as a result. [1,2,3] == [1,2,3] ==> false
+
. valueOf
Object
Array
, . toString()
. , {}
, , . , +[]
, toString()
, 0. {}+[]+{}+[1] ==> +[]+{}+[1] ==> 0 + {} + [1] ==> 0 + '[object Object]' + [1] ==> '0[object Object]' + [1] ==> '0[object Object]' + '1' ==> '0[object Object]1'
!+[]+[]+![] ==> (!+[]) + [] + (![]) ==> !0 + [] + false ==> true + [] + false ==> true + '' + false ==> 'truefalse'
-
Date
. Date.valueOf()
Unix. new Date(0) - 0 ==> 0 - 0 ==> 0
+
. Data
, toString()
, valueOf()
. new Date(0) + 0 ==> 'Thu Jan 01 1970 02:00:00 GMT+0200 (EET)' + 0 ==> 'Thu Jan 01 1970 02:00:00 GMT+0200 (EET)0'
Source: https://habr.com/ru/post/347866/
All Articles