ref – https://www.sitepoint.com/automatic-type-conversion/
http://www.discoversdk.com/blog/data-type-conversion-in-javascript
https://www.digitalocean.com/community/tutorials/how-to-convert-data-types-in-javascript
As a programming language, JavaScript is very tolerant of unexpected values. Because of this, JavaScript will attempt to convert unexpected values rather than reject them outright. This implicit conversion is known as type coercion.
Type Checking
In JavaScript you can check the type of an object or data contained in a variable at runtime. To check the type of some variable, object, or literal value use the typeof operator with the variable, value, or object as the argument to the operator. This operator returns the type as a string.
Note: typeof in JavaScript is not a function—it an operator. But, you can use it like a function. In this case () is not used as a calling operator, but rather as an encapsulation for some code on a single line.
typeof in JavaScript is not a function—it an operator
1 2 3 |
var val = "I am obviously a string"; var type = typeof val; console.log(type); |
Implicit Conversion
JavaScript provides automatic type conversions.
But that doesn’t mean that you can sit idle and do nothing explicitly.
Again, it is a best practice to convert data types explicitly to avoid bugs in your program. Often, for automatic or implicit conversion you will not get your expected result.
JavaScript is a forgiving language. It will not reject the values directly and will not stop further execution. It will convert them automatically and provide you with some result. That means JavaScript coerces data types to be converted when they need to be in another form. Look at the examples below to see why it is bad to fall back to automatic type conversion or automatic coercion.
2+”2″=”22″
2 is a number and “2” is a string. If we add them together with the + operator JavaScript will try to coerce them to one type and then apply the operation. If JavaScript converts both of them to number then we get 4, but if JavaScript coerces them to string then we get a string “22”.
What do you see as a result? It provided us with ’22’. But that behavior is not always expected or tolerated. In the example above it can be assumed that in JavaScript mathematical operations on a mix of numbers and strings will return a string. Wrong! That is not always the case.
2 * “2” = 4
This time it returned a number instead of string.
Without just assuming, let’s check with the typeof operator the type of the output.
typeof (2 * “2”)
Outputs: ‘number’
So, automatic type conversion or type coercion is not always a good thing.
But, in many places inside JavaScript environments we only need the string value and we can easily understand what the result is gonna be.
For example, in a browser environment calling alert() with some value inside, it will convert the value to a string and display it to the user. After evaluating the lines of code or the statements, alert() gets a single value at the end. So, it is safe to convert a single value to a string without worrying unless otherwise warned or specified.
Explicit Conversion
As discussed in the previous section, explicit conversion is the best and safest way to go. In this section we will see different ways of converting different types of values.
Strings
String is the most widely used type to which we convert different data. To send data over the network or to save it into a file we cannot send or write it as a pure original JavaScript type. We need to convert it to a string and the receiving system can optionally convert it to bytes or resort to that system’s native type system.
To convert other data to string data type we can call String() with the value or variable of that data. Let’s say we want to convert number 100 to a string. Below are demonstration of the both ways described above.
1 2 3 4 5 6 7 |
String(100) // "100" var i = 100; i.toString(); // "100" (100).toString(); // "100" |
When we have a object, we call the toString() method on that variable or object
String(a) calls toString on object a like this a.toString().
When this happens, it will get object a’s highest __proto__, which is Object.
Let’s set up the example. We have a literal object a given like so:
1 2 3 4 5 6 7 8 9 10 |
let a = { name: "default" } function User() { var name = "default"; var location = "Shenzhen, China"; } a.__proto__ = User.prototype |
When we have a User constructor function. It has a User.prototype object
our literal object a’s __proto__ is then assigned to it.
We call toString() on it. String(a), also does the same thing.
1 |
console.log(String(a)); // [object Object] |
Via prototype hierarchy, it looks at object a and does not find a toString.
It then goes to a’s __proto__, (User.prototype), and does not find toString there either.
It goes up User.prototype’s __proto__, (Object.prototype), and sees the default toString().
Hence, it calls Object.prototype’s toString().
This is because Object is the top most base that all objects in javascript derives from.
We need to over-ride it in order to return something more useful. Say our object a’s __proto__ references User.prototype
1 2 3 |
User.prototype.toString = function() { return "object type: User"; } |
Now, when you call a.toString(), it’ll look at object a. does not exist, then it’ll go up to a’s prototype (User.prototype) and finds it there.
Numbers
1 2 3 4 5 6 7 |
console.log(Number("200")); // number strings ok 200 console.log(Number(true)); // 1 console.log(Number(false)); // 0 console.log(Number(undefined)); // Nan console.log(Number(null)); // 0 console.log(Number("hadoken!")) // word strings are Nan console.log(Number(a)) // objects are Nan |
Boolean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
console.log(Boolean("")); // false console.log(Boolean("hehe")); // true console.log(Boolean("0")); // true console.log(Boolean("1")); // true // 0 number is false // > 0 number is true console.log(Boolean(0)); // false console.log(Boolean(3.14)); // true console.log(Boolean(null)); // false console.log(Boolean(undefined)); // false console.log(Boolean(a)); // true console.log(Boolean({})); // true |
JavaScript is a “loosely typed” language, which means that whenever an operator or statement is expecting a particular data-type, JavaScript will automatically convert the data to that type.
JavaScript values are often referred to as being “truthy” or “falsey”, according to what the result of such a conversion would be (i.e. true or false). The simplest way to think of it is like this:
a value is truthy unless it’s known to be falsey; and in fact there are only six falsey values:
false
undefined
null
0 (numeric zero)
“” (empty string)
NaN (Not A Number)
Notable exceptions are “0” (string zero) and all types of object — which are truthy —
Remember, for strings, any non-empty strings are true. the empty string “”, is false.
1 2 3 |
console.log(Boolean(true)); // true console.log(Boolean(false)); // false console.log(Boolean("false")); // true |
The Condition Shortcut
The if() converts its expression to a boolean, and since objects always evaluate to true while null evaluates to false, we can use a condition like that to test for the existence of DOM elements:
1 2 3 4 5 6 7 8 9 |
var element = document.getElementById("whatever"); if(element) { //the element exists } else { //the element doesn't exist } |
That will always work reliably when dealing with DOM elements, because the DOM specification requires that a non-existent element returns null.
However, other cases are not so clear-cut, like this example:
1 2 3 4 5 6 7 |
function doStuff(foo) { if(foo) { ... } } |
Conditions like that are frequently used to mean “if the foo argument is defined”, but there are several cases where that would fail — namely, any cases where foo is a falsey value. So if, for example, an empty string:
1 2 3 4 5 6 7 8 9 10 11 12 |
let param = String(""); // empty string console.log(param) function doStuff(foo) { if (foo) { console.log("object is defined!") } else { console.log("NOT DEFINED!") } } doStuff(param) //not defined |
then the conditional code would not be executed, even though foo is defined.
This is what we want instead:
1 2 3 4 5 6 7 |
function doStuff(foo) { if(typeof foo != "undefined") { ... } } |
like so:
1 2 3 4 5 6 7 8 9 10 |
let param2 = String("") // let param2 = Boolean(false) function doStuff2(foo) { if(typeof foo != "undefined") { console.log("doStuff2 - object is defined!") } } doStuff2(param2) |
Arguments (and other variables) which have not been defined, have a data-type of “undefined”. So we can use the typeof comparator to test the argument’s data-type, and then the condition will always pass if foo is defined at all. The if() expression is still evaluating a boolean, of course, but the boolean it’s evaluating is the result of that typeof expression.
The Assignment Shortcut
1 |
var x = foo || bar; |
Logical operators do not return a boolean, but they do still expect a boolean, so the conversion and evaluation happens internally. If foo evaluates to true then the value of foo is returned, otherwise the value of bar is returned. This is immensely useful.
This expression is commonly seen in event-handling functions, where it’s used to define an event argument according to the supported model:
1 2 3 4 |
element.onclick = function(e) { e = e || window.event; }; |
So e is evaluated as a boolean, and that will be truthy (an event object) if the event-argument model is supported, or it will be falsey (undefined) if not; if it’s truthy then e is returned, or if not then window.event is returned.
However..!
But expressions like this are equally prone to failure, in cases where the truthy-ness of the data isn’t known. For example, another common use-case is to define defaults for optional arguments, but this is not good:
1 2 3 4 |
function doStuff(foo) { foo = foo || "default value"; } |
Now if you know for sure that foo will always be either a string or undefined, and assuming that an empty string should be treated as undefined, then that expression is safe. But if not, it will need to be re-defined to something more precise, like this for example:
1 2 3 4 5 6 7 |
function doStuff(foo) { if(typeof foo != "string") { foo = "default value"; } } |
By testing the type against “string” we can handle multiple cases — where foo is undefined, and also where it’s mis-defined as a non-string value. In that case we also allow an empty string to be valid input, but if we wanted to exclude empty strings, we’d have to add a second condition.
1) if its not a type string, we move forward and assign it a string default value
2) if variable is a string but empty, we move forward and assign it a string default value
1 2 3 4 5 6 7 |
function doStuff(foo) { if(typeof foo != "string" || foo == "") { foo = "default value"; } } |
Another example
Here, we’re first checking to see if timestamp has value, if not, then assign it a new Date.
However, it would fail if the input is 0, because 0 is a falsey value. However, 0 is also a valid timestamp.
It just means 1/1/1970.
1 2 3 4 |
function doDateStuff(timestamp) { timestamp = timestamp || new Date().getTime(); } |