To help you understand better, let’s quickly revisit types in JavaScript. Variables in JavaScript do not have types; values do. JavaScript has eight basic value data types, and they are divided into two categories, primitive and non-primitive.
Primitive Types:
- Undefined
- Null
- Boolean
- String
- Symbol
- Number
- BigInt
Non-Primitive Types (Reference types):
- Object
- Array
- 
Function Arraysandfunctionsare subtypes of theobjecttype.
One major difference between primitive and non-primitive values is that primitive values are immutable after creation while non-primitive values are mutable.
Let’s take an example:
// Let's alter the value of the string assigned to the variable person.
let person = "ifeoma"
// Here it simply made a copy and then altered the copied value.
console.log(person.toUpperCase()) // IFEOMA
// It didn't change the original value.
console.log(person) //  ifeoma
From the example above, when we tried to alter the value, it only made a copy of the variable person  and changed it, but it didn’t change the already existing  string  value because it is a primitive.
On the other hand, the variable assigned to a primitive value can be changed. Therefore, it can be reassigned so that it points to a new value but the existing value it holds cannot be changed.
let person = "ifeoma"
person = "sylvia"
console.log(person)  // sylvia
In the example above, we assigned a new  string  value to the variable  person  so that it no longer points to the initial  string  value  ifeoma .
Let’s try to mutate a non-primitive:
let array = [ "Jay Pritchet", "Phil Dunphy" ]
let array2 = array
array.push("Claire Pritchet")
console.log(array2) // [ "Jay Pritchet", "Phil Dunphy", "Claire Pritchet" ]
In the above example, we made  array  a reference to  array2 . Emphasis on reference, which means that even after we modified the data in array by adding a new item to it, logging  array2  shows the new item added to  array . 
This is because the variable array2 is referencing the address of the variable array. 
This behavior is expected from all non-primitive value types.
Another difference between primitives and non-primitives is that primitives are stored by value while non-primitives are stored by reference.
The  typeOf  operator is a built-in utility used to check the type of value assigned to a javascript variable. 
The
typeOfoperator always returns a string type.
Let’s take a look at how values are changed from one type to another.
Coercion
Coercion refers to the process of converting values from one type to another(such as  string  to  number ).
Using inbuilt functions(Number(), String() etc.) you can be obvious about your intention to convert a value from one type to another(explicit coercion) or let Javascript automatically handle the conversion for you(Implicit coercion). 
Coercion always results in either  strings ,  numbers , or  booleans . Understanding coercion will help you avoid problems that can occur in your code.
Let's see some examples.
Implicit Coercion
5 - "1" // 4  JavaScript coerced the string 1 to a number.
10 * false // 0  Javascript coerced the boolean false to 0.
10 + true // 11  The boolean true is coerced to a number 1.
Explicit Coercion
Number('5') - Number('2') // 3 Here we are explicitly converting both strings to numbers first using the Number() method.
To fully understand how coercion happens, we need to talk about Abstract Operations.
Abstract Operations are the fundamental building block that makes up how we deal with type conversion. - Kyle Simpson
Abstract Operations
According to the ECMAScript specification, abstract operations are not part of the language specification, but they are responsible for performing type conversion in Javascript. Whenever coercion (implicit or explicit) occurs, one or more internal operations, known as abstract operations, are performed.
We will look at these four primary abstract operations, but you can find the rest of them in the spec.
- ToPrimitive()
- ToString()
- ToNumber()
- ToBoolean()
ToPrimitive()
When a non-primitive or reference value is used in the context where a primitive is required, the JavaScript engine calls the  ToPrimitive()  abstract operation. 
When converting non-primitive types to primitives, the abstract operation ToPrimitive() is invoked to handle the operation.
Let's see how non-primitive values are converted to primitives.
The spec informs us that the  ToPrimitive()  abstract operation takes two arguments. 
- An input
- An optional PreferredType hint
The PreferredType hint can be either one of these -
string,number,default.
If you are performing a numeric operation and the  ToPrimitive()  operation is invoked, number will be sent as the hint. If you are working with strings, it will send  string  as the hint. 
When  ToPrimitive() is called with no hint present, it'll send  default  as a hint, and this will behave as if the hint were  number  (unless it's a  Date  which defaults to  string ).
If the argument is already a primitive value, then it will be returned without conversion. Let's take a look at how the ToPrimitive algorithm works.
There are two methods available on every object type used to convert them from non-primitives to primitives:
- valueOf() — This is to retrieve the primitive value associated with an object.
- toString()
Number Algorithm
If the hint is  number , it calls the valueOf()  function first, and if the returned value is primitive, it'll use it. If the object has no primitive value,  valueOf()   returns the object back then the  toString()  function gets called. Its value will be used if it is primitive; otherwise, it would result in a type error.
String Algorithm
If the hint is  string , the order is reversed compared to the number algorithm. It calls the non-primitive  toString()  function first, and if it gets a string representation, it'll just use it; otherwise, it'll try the  valueOf() method to see if the object has any primitive value.
Default Algorithm
If no hint is sent, it sets the default hint to  number , or it is set to  string  if it is a  Date . 
The algorithms within JavaScript are inherently recursive. This means that if the
ToPrimitive()operation gets invoked and the return result is not a primitive, it will keep getting invoked until it returns a primitive or an error.
ToString()
This abstract operation takes any value and converts it to a representation of the value in  string  form.
| Argument | Result | 
|---|---|
| Null | “null” | 
| Undefined | “undefined | 
| true | “true” | 
| false | “false” | 
| “Hi” | “Hi” | 
| Symbol | Throw a TypeError exception. | 
As seen above, built-in primitives have natural stringification, but if the  ToString()  operation is called on an  object  type, it will invoke the ToPrimitive() operation, and pass string as the hint.
As explained earlier, this will call the  toString()  first, and if it gets a string representation, it'll just use it; otherwise, it'll try the  valueOf() method.
By default, regular JavaScript objects have their built-in  toString()  method (located in Object.prototype.toString()) that is called when an object is used in a manner in which a string is expected and this will return their internal [[Class]] property (e.g [object Object]). 
Unless you specify your toString() method, if you use an object in a string-like way, the toString() method on its object prototype will be called. This will return a string with the [object Type] format where  Type  is the object type. 
Let’s see an example:
const obj = {}
obj.toString() // [object Object]
Although arrays are subtypes of the object type, the array object has a built-in  toString()  method that overrides the default  Object.toString()  method and returns a  string  representation containing each array element separated by a comma. This toString() method lives on the Array’s prototype  as Array.prototype.toString().
Here is an example:
// Calling toString() explicitly on an array
let array = []
array.toString() // ""  It returns an empty string.
let array1 = [1, 2, 3]
array1.toString() // "1,2,3"  It returns a string containing each element in the array seperated by a comma.
In a situation where you want to get the object class, you need to skip the default override behavior of Array.prototype.toString in favor of Object.prototype.toString() . 
You have to pass the  array  in the  call() method to change the context from Array to Object.
console.log(Object.prototype.toString.call([1, 2, 3])) // [object Array] 
ToNumber()
Whenever we perform a numeric operation, and one or both operands aren't numbers, the  ToNumber()  abstract operation will be invoked to convert it to a value of type  number . 
Let's see some examples:
| Argument | Result | 
|---|---|
| undefined | NaN | 
| null | 0 | 
| true | 1 | 
| false | 0 | 
| “” | 0 | 
| “.” | NaN | 
| “1” | 1 | 
| BigInt | Throw a type error exception. | 
| symbol | Throw a type error exception. | 
| object | 1.  ToPrimitive(argument, number). 2. Return ? ToNumber(primValue). | 
As seen from the table above, when  ToNumber()  is called on a non-primitive (any of the object types) value, it is first converted to its primitive equivalent by invoking  ToPrimitive() abstract operation and passing  number  as the PreferredType hint.
The return value from the  ToPrimitive()  operation will then be coerced into a  number  by the  ToNumber() abstract operation. If it still doesn't result in a primitive value, it throws an error.
Let's take an array with an empty string as an example.
ToPrimitive( [""], number) // It first calls the ToPrimitive abstract operation on it and pass number as the hint.
[""].valueOf() // [""]  Because  the hint is number, it calls valueOf first and this basically returns itself. So we still have the array with an empty string which isn’t a primitive.
[""].toString() // ""   It then calls the toString() function next and this will end up producing an empty string "".
ToNumber("") // 0   Next it calls ToNumber() and passes the empty string "" as an argument. As seen from the table above, that would result to 0.
ToBoolean()
The abstract operation   ToBoolean()  is called to convert an argument to a Boolean type whenever we use a value that is not  Boolean  in a place that needs a   Boolean . The  ToBoolean()  abstract operation does not invoke the  ToPrimitive()  or any of the other abstract operations.
It just checks to see if the value is either falsy or not. There is a lookup table in the spec that defines a list of values that will return  false  when coerced to a  boolean . They are called falsy values.  
These are the falsy values:
| Argument Type | Result | 
|---|---|
| undefined | false | 
| null | false | 
| false | false | 
| NaN | false | 
| 0 | false | 
| -0 | false | 
| “” | false | 
Values that are not on the list of falsy values are truthy values.
Conclusion
Languages that take the first position about their rules are referred to as "strongly typed" because they are strict about not allowing you to break the rules.
Since JavaScript is not one of them, it is referred to as weakly or loosely typed because it gives room for a lot of flexibility in terms of implicit coercion, and you do not have to specify the type of your variables explicitly.
Like any other language, Javascript has its rules, and the rules that govern the type system of a language exist to help us. It is up to us to learn them to avoid unnecessary mistakes.
Thank you! I hope you enjoyed reading as much as I enjoyed writing ❤️.
 
 
              
 
    
Top comments (1)
I just started Learning JS but I think coercion is only implicit right??