JavaScript Implicit Type Conversions You Didn't Know
This article examines JavaScript’s implicit type conversion mechanisms, illustrating a quirky yet functional code example, detailing conversion rules for symbols, objects, arrays, numbers, booleans, and undefined/null, and highlighting common pitfalls and practical coding tricks.
JavaScript is a dynamic, weakly typed language that performs many implicit type conversions. This article starts with a seemingly crazy but valid code snippet and then explains the rules behind JavaScript’s implicit coercion.
Crazy but Valid Code
The following expression works because of JavaScript’s type conversion rules:
// a
(![]+[])[+!![]] === "a"Conversion Rules
Symbol
Operation Rule
[]
Empty array, treated as truthy.
!
Logical NOT, converts operand to boolean and negates it.
!!
Double NOT, forces a value to boolean.
+
When one operand is a string (or can be converted to a string), the other operand is also converted to a string and concatenated.
Conversion Steps
Symbol
Computation Process
Result
![]
Empty array
[]is truthy; applying
!yields
false.
(false+[])[+!![]]
![] + []
falseconcatenated with
[]becomes the string "false".
("false")[+!![]]
!![]
Double NOT converts to
true.
("false")[+true]
+!![]
Converts
trueto the number
1.
("false")[1]
(![]+[])[+!![]]
Indexes the string "false" at position 1, yielding the character
"a".
"a"
Further Exploration
Using only the characters ! , ( , ) , [ , ] , and + , developers can construct many obscure expressions. The site JSFuck demonstrates this with thousands of characters to produce simple strings.
Type Conversion Rules
Basic Implicit Conversions
Arithmetic Operators
When the + operator involves a string, the other operand is converted to a string; otherwise, operands are converted to numbers.
// + with a string converts both to strings
console.log(1 + '1') // '11'
// other cases
console.log(1 + true) // 2 : number + boolean
console.log(true + false) // 1 : boolean + boolean
console.log(1 - false) // 1 : number - boolean
console.log(true - false) // 1 : boolean - boolean
console.log(-1 * '1') // -1 : number * string
console.log(-1 / true) // -1 : number / boolean
console.log(2 ** ('1' + 0)) // 1024 : number ** (string + number)
console.log(100 % ('1' + 0)) // 0 : number % (string + number)Logical Operators
The NOT operator ( ! ) converts its operand to boolean. The OR ( || ) and AND ( && ) operators perform short‑circuit truthy/falsy evaluation.
// NOT
console.log(!true) // false
console.log(![]) // false
console.log(!!{}) // true
// OR and AND
console.log(0 || 1) // 1
console.log(1 || 0) // 1
console.log(0 && 1) // 0
console.log(1 && 0) // 0Bitwise Operators
Bitwise operators ( & , | , ^ , ~ , << , >> ) first convert operands to 32‑bit integers.
console.log(2 & 3) // 2 (010 & 011 = 010)
console.log(2 | 3) // 3 (010 | 011 = 011)
console.log(2 ^ 3) // 1 (010 ^ 011 = 001)
console.log(~2) // -3 (bitwise NOT)
console.log(2 << 1) // 4 (010 << 1 = 100)
console.log(4 >> 1) // 2 (100 >> 1 = 010)Complex Implicit Conversions
Object to Primitive
When an object participates in an operation, JavaScript calls its valueOf() and/or toString() methods to obtain a primitive.
let obj = {
toString() { return '42'; },
valueOf() { return 10; }
};
console.log(obj + 10); // 52 (valueOf() returns 10, then string concatenation)
console.log(String(obj)); // '42'Symbol Type
Symbols cannot be implicitly converted to strings or numbers; attempting to do so throws a TypeError .
let sym = Symbol('example');
try { console.log('symbol: ' + sym); } catch(e) { console.log(e); }
try { console.log(sym + 10); } catch(e) { console.log(e); }
console.log(String(sym)); // 'Symbol(example)'Common Implicit Conversion Pitfalls
Array and Number Operations
console.log([] + 1); // '1'
console.log([1] + 1); // '11'
console.log([1,2] + 1); // '1,21'Empty array becomes an empty string, a single‑element array becomes the element’s string, and a multi‑element array joins its elements with commas before concatenation.
Empty Object and Boolean Comparison
console.log({} == true); // false
console.log({} == false); // false
console.log([] == true); // false
console.log([] == false); // trueWhen compared to a boolean, both sides are converted to numbers; {} becomes NaN , while [] becomes 0 .
undefined and null
console.log(undefined + 1); // NaN
console.log(null + 1); // 1
console.log(undefined == null); // trueundefined cannot be converted to a number, yielding NaN . null is treated as 0 in arithmetic, and both values are considered equal with == .
Implicit Conversions in Real‑World Scenarios
JSON and Object Conversion
let jsonStr = '{"a": 1, "b": "2"}';
let obj = JSON.parse(jsonStr);
console.log(obj.a + obj.b); // '12' (number + string => string concatenation)Type Conversion in Conditional Statements
let x = 0;
let y = '0';
if (x == y) { console.log('x == y'); } // prints
if (x === y) { console.log('x === y'); } // does not print
if (x || y) { console.log('x || y'); } // prints '0'Loose equality ( == ) coerces y to a number, making the comparison true; strict equality ( === ) does not. The logical OR returns the first truthy operand.
Conclusion
The article demonstrates the power and complexity of JavaScript’s implicit type conversion, showing how seemingly bizarre code can be valid and how understanding these rules is essential for writing robust JavaScript.
大转转FE
Regularly sharing the team's thoughts and insights on frontend development
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.