February 13, 2019
Type (or data type) is a characteristic of a value affecting what kind of data it can store — for example in JavaScript a Boolean only holds true/false values, whereas a String holds text strings, a Number holds numbers of any kind, and so on.
A value’s data type also affects which operations are valid on that value. For example, an integer can be multiplied by an integer, but not by a string. from MDN Web Docs
Primitives are the built-in immutables types:
If you want to know the actual value in a variable you can use typeof =>
typeof 36 // "number"
Natives types are primitive wrapper objects and they were created to simplify developers life (specially java developers):
Some of the natives types are built-in objects and others created by developers.
var a = 'hello' // primitive
a.toUpperCase() // "hello"
var b = new String('hello') // object
b.toUpperCase() // "HELLO"
var arr = new Array(2) // with 2 empty slots
arr.push(1) // [undefined, undefined, 1]
arr[0] // undefined
arr[2] // 1
var arrLit = [1, 2, 3, 4, 5] // create array using literal
This is a Javascript feature where a value is converted from one type to another (type conversion) implicitly and always results in one of the scalar primitives (string, number or boolean).
ToString will handle coercion of any non-string value to a string representation
// applying to primitives values
String(null) // "null"
String(undefined) // "undefined"
String(true) // "true"
String(false) // "false"
String(0) // "0"
String(-0) // "0"
// applying to arrays
String([]) // ""
String([1, 2]) // "1,2"
;[1, 2]
.toString() // "1,2"
[(null, undefined)].toString() // ","
;[[], [], []].toString() // ",,"
// applying to objects has no representation
var obj = { a: 1, b: 2 }
obj.toString() // [object Object]
ToNumber is the abstract operation that handle coercion of non-number values to a number representation
Number('') // 0
Number('-0') // -0
Number('0') // 0
Number('007') // 7
Number(007) // 7
Number('0,9') // NaN
Number('0.9') // 0.9
Number('0xaa') // 170
Number('.') // NaN
Number('mau') // NaN
Number([1, 2, 3]) // ToString -> ToNumber -> NaN
Objects and arrays will first be converted to their primitive value, so the ToPrimitive abstract operation will look for valueOf() method to return a primitive value that will be used for coercion. And if toString() is available then it will provide the value for the coercion.
var a = {
valueOf: function() {
return 36
},
}
Number(a) // 36
ToBoolean will handle values coercion to boolean, JS spec defines a specific list of values that coerce to false (falsy values)
Any value not present in the above list will be called a truthy value
// falsy
Boolean(0) // false
Boolean(-0) // false
Boolean(+0) // false
Boolean(undefined) // false
Boolean(null) // false
Boolean(NaN) // false
Boolean('') // false
// truthy
Boolean("''") // true
Boolean('false') // true
Boolean(1) // true
Boolean(2) // true
Boolean([]) // true
Boolean({}) // true
Is when you watch the code and you know what type conversion is being done, they are obvious and make the code more understandable.
// coerce number to string using ToString rules
var s = 36
String(s) // "36"
// coerce number to string using .toString()
s.toString() // "36" <- js automatically boxes number in an object wrapper
// coerce string to number using ToNumber rules
Number('36') // 36
// coerce string to number using _+_ unary operator
var a = +'36' // 36
// do not use + operator immediately adjacent to other operators
// Date to number using + operator
var d = new Date('2019-02-11 10:00:00')
;+d // 1549890000000
var ts = +new Date() // 1549890000000
var ts = Date.now() // USE THIS!!!
// coerce to Boolean using _!_ unary operator
var t = '1'
!!t // true
var f = ''
!!f // false
Explicit boolean coercion with ! unary operator: !!“1” the second ! operator (from left to right) apply ToBoolean to what is on it right side if it is not boolean, and the first ! negates the boolean obtained
!!"1"
- "1" is true
- !true is false
- !false is true
result is true
The ~ unary operator can also be used to do an explicit boolean coercion when used with indexOf(..) method
~n = -(n + 1) => ~26 = -(26 + 1) = -27
Failure value -1 is returned by indexOf(..) when no substring is found in another string
~"some string".indexOf("substring")
"some string".indexOf("substring") returns -1
~"some string".indexOf("substring") => -(-1 + 1) => -0 => 0 (bitwise not arithmetic) => falsy
Are any type conversions that are not obvious, making the code more difficult to understand because you don’t know what goes on behind.
The intent of the implicit coercion is:
Implicit coercion from string to number
// -, * and / operators are defined just to numeric operations
var a = '23'
var b = a - 0 // 23
var c = a / 1 // 23
var d = a * 2 // 46
// first coerced to string and then coerced to number
var e = [24] - [1] // 23
var f = [24, 1] - [1, 1] // NaN <- Number("24,1") - Number("1,1")
Implicit coercion from number to string
// using + operator
var a = 23
var b = a + '' // "23"
// ToNumber rules on objects
// The valueOf() operation on the array will fail to produce a simple primitive,
// so it then falls to a toString() representation "1,2" and "3,4"
// and finally + concatenates both string
var a = [1, 2] + [3, 4] // "1,23,4"
var a = {
valueOf: function() {
return 36
},
toString: function() {
return 23
},
}
a + '' // "36" <-- invokes valueOf(..)
String(a) // "23" <-- invokes toString()
Implicit coercion from boolean to number
//
var a = 1 + true // 2 <-- true coerced to 1
var a = 1 + false // 1 <-- false coerced to 0
Implicit coercion from anything to boolean are required in test expressions:
var a = 36
var b = 'hello'
var c // undefined
var d = null
if (a) {
// 36 -> truthy
console.log('printed') // printed
}
while (c) {
// undefined -> falsy
console.log('never run')
}
c = d ? a : b // false ? 36 : "hello" -> "hello"
c // "hello"
// (( 36 && null) || "hello")
// ((true && false) || true)
// false || true
// true
if ((a && d) || c) {
console.log('printed') // printed
}
|| and && operators select the value of one of the two operands expressions, || operator is commonly used to have a default value if the first evaluation is falsy
var a = 1
var b = 'hello'
var c = undefined
a || b // 1
a && b // "hello"
c || b // "hello"
c && b // undefined
var name
var greeting = 'hello ' + (name || 'john') // "hello john" <- bc name is undefined then falsy
== operator allows coercion in the equality comparison so if you are comparing two values of different type you may want to use == coercion, if not you can go with === strict equals.
// string to number
var a = 1
var b = '1'
a === b // false because === doesn't allow coercion
a == b // true because "1" is a string and is coerced with ToNumber rules
// anything to boolean
var c = '36'
var d = true
// "36" == true when an operand is boolean is coerced using ToNumber rules Number(true) => 1
// "36" == 1 now there is a string so is coerced with ToNumber rules too
// 36 == 1? No -> false
c == d // false
a == d // true "1" == 1 -> 1 == 1
// null and undefined
var e = null
var f
e == f // true
e == null // true
f == null // true
f == undefined // true
// using others false values
e == false // false
f == false // false
e == '' // false
f == '' // false
e == 0 // false
f == 0 // false
// objects to non-objects
// objects are coerced with the ToPrimitive algorithm
// remember valueOf() and toString()
var g = 36
var h = [36]
// 36 == [36]
// 36 == "36"
// 36 == 36
g == h // true
var i = 'hello'
var j = Object(i) // unboxed to "hello" using ToPrimitive
i == j // true
i === j // false
typeof i // "string"
typeof j // "object"
if(a == null){..}
instead of if(a === undefined || a === null){..}
Example of a crazy coercion result [] == ![] is true
How can a value be false and true at the same time? They can’t
Written by Mauricio Galdames. Twitter