Why Does [] == ![] Evaluate to True? Unraveling JavaScript Type Conversion
This article explains JavaScript’s explicit and implicit type conversion mechanisms—including Number(), String(), Boolean(), toString and valueOf—through detailed code examples and clarifies puzzling expressions like [] == ![] and {} == !{}.
Forced Type Conversion
Number()
Primitive arguments
Number(123) // 123
Number('123') // 123
Number('123abc') // NaN
Number('') // 0
Number(true) // 1
Number(false) // 0
Number(undefined) // NaN
Number(null) // 0Number() is stricter than parseInt. When the string cannot be fully parsed, it returns NaN:
parseInt('32 abc') // 32
parseInt('0x11 abc') // 17
Number('32 abc') // NaN
Number('0x11 abc') // NaNObject arguments
Number({a: 1}) // NaN
Number([1, 2, 3]) // NaN
Number([5]) // 5When an object provides both valueOf and toString, Number() follows a specific order:
const obj = {
toString() { return 1; },
valueOf() { return 2; }
};
console.log(Number(obj)); // 2If valueOf returns an object, toString is used instead:
const obj = {
toString() { return 1; },
valueOf() { return {}; }
};
console.log(Number(obj)); // 1When both methods return objects, a TypeError: Cannot convert object to primitive value is thrown.
const obj = {
valueOf() { return {}; }
};
console.log(Number(obj)); // NaN (no error because only valueOf is present)For an empty object, the default Object.prototype.toString is invoked:
// Number({})
Object.prototype.toString.call({}) // "[object Object]"
Number("[object Object]") // NaNFor an empty array, Array.prototype.toString yields an empty string, which converts to 0:
// Number([])
Array.prototype.toString.call([]) // ""
Number('') // 0String()
Primitive arguments
String(123) // "123"
String('abc') // "abc"
String(true) // "true"
String(undefined) // "undefined"
String(null) // "null"Object arguments
String({a: 1}) // "[object Object]"
String([1, 2, 3]) // "1,2,3"When an object defines both toString and valueOf, String() prefers toString first:
const obj = {
toString() { return 1; },
valueOf() { return 2; }
};
console.log(String(obj)); // "1"Boolean()
Falsy values ("falsey")
undefined
null
0 // +0 and -0
NaN
false
''All other values are truthy:
Boolean([]) // true
Boolean({}) // true
Boolean(new Error()) // true
Boolean(Symbol()) // trueImplicit (Automatic) Type Conversion
Automatic conversion to Boolean
Control‑flow keywords and logical operators coerce their operands to Boolean.
Automatic conversion to String
When the + operator involves a string, the other operand is converted to a string.
'5' + 1 // "51"
'5' + true // "5true"
'5' + {} // "5[object Object]"
'5' + [] // "5"Automatic conversion to Number
All arithmetic operators except + (when used for concatenation) coerce operands to numbers.
'5' - '2' // 3
'5' * '2' // 10
true - 1 // 0
false - 1 // -1
null + 1 // 1
undefined + 1 // NaNRelational operators ( ==, !=, ===, etc.) also perform numeric conversion when needed.
1 == true // true
'1' == true // true
'1' == 1 // true
[1] == 1 // true
[] == false // true
[] == null // falseSpecial Values
Infinity
Number(Infinity) // Infinity
1 / 0 // Infinity
1 / Infinity // 0
Infinity === Infinity // true
Infinity === -Infinity // false
0 === -0 // true
0 / 0 // NaNNaN
NaN == NaN // falseundefined and null
null === null // true
undefined === undefined // true
undefined == null // true
undefined === null // falseSummary
Now we answer the initial puzzles. [] == ![] evaluates to true because [] converts to an empty string '', which becomes 0; ![] is false, which also becomes 0, so 0 == 0 is true.
// [] == ![]
[].toString() // ''
Number('') // 0
![] // false
Number(false) // 0
0 == 0 // true {} == !{}evaluates to false because {} converts to "[object Object]", which becomes NaN; !{} is false (=> 0), and NaN != 0.
// {} == !{}
({}).toString() // "[object Object]"
Number('[object Object]') // NaN
!{} // false
Number(false) // 0
NaN != 0 // false overallFurther examples such as {} + {}, [] + {}, and {} + [] produce string concatenations according to the same conversion rules; you can experiment at jsisweird.com .
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
