JavaScript Overview — Values and data types
In the previous part, we learned some history about JavaScript and covered one of the most important concepts: not everything you see in JavaScript code is JavaScript.
In this part, I will start to cover small parts of JavaScript and one of them is “the primitive values” that we use as the building blocks for any program.
You may heard “In JS everything is an object”. It is a big misconception because most of the values in JS can behave as an object.
JavaScript has 8 built-in types. The set of types in the JavaScript language consists of primitive values and objects.
- Primitive values (atomic pieces of data): Boolean type, Null type, Undefined type, Number type, BigInt type, String type, Symbol type
- Objects
In JavaScript, variables don’t have types — values have types. Variables can hold any value, at any time.
All primitive values are immutable, meaning that you cannot mutate their values. When we reassign a variable, giving it a new value, we are not changing the value itself; we are only changing which value the variable refers to. It’s important to understand.
Numbers
There are three special values in JavaScript that are considered numbers but don’t behave like normal numbers.
The first two are Infinity
and -Infinity
, which represent the positive and negative infinities.”
The third is NaN
and it’s stands for “not a number,” even though it is a value of the number type.
Also the most common issue with JavaScript numbers is:
0.1 + 0.2; // 0.30000000000000004
0.1 + 0.2 === 0.3 // will be always false
So we should be really careful when we work with JavaScript numbers.
null and undefined
The difference in meaning between undefined
and null
is an accident of JavaScript’s design.
Everything tracked by JavaScript is bound. In fact, the definition of undefined
means JavaScript cannot find a bound identifier.
You can think undefined
means a variable has been declared but has not yet been assigned a value (BUT IT’s NOT ALWAYS the TRUE) and null
is an assignment value.
typeof and instanceof
The typeof
operator tests whether value belong to one of 7 basic types: number
, string
, boolean
, object
, symbol
, function
or undefined
. Where the “object"
belong to all objects (except functions, which are objects but have their own value in typeof
operator), and also null
value and arrays (for null
it’s a bug, but this bug is so old, so it’s become a standard). It doesn’t rely on constructors and can be used even if a value is undefined. But it’s doesn’t give any details about objects. So if you needed it, go to instanceof
.
The instanceof
operator is used to determine whether or not a type is of a particular constructor function.
Falsy values
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.
A falsy value is a value that is considered false
when encountered in a Boolean context.
Type Conversion aka Type Coercion
When an operator is applied to the “wrong” type of value, JavaScript will quietly convert that value to the type it needs, using a set of rules that often aren’t what you want or expect. This is called type coercion.
Type conversion is similar to type coercion because they both convert values from one data type to another with one key difference — type coercion is implicit whereas type conversion can be either implicit or explicit.
We recommend using the three-character comparison (===
) operators instead of two-character (==
) to prevent unexpected type conversions, because ===
just do value comparison and dosen’t do any coversions. But the ===
operator does have some nuance and it’s better to know them.
Learn more type coercion:
Boxing and Native constructors
How do primitive types in Javascript have methods and properties?
Object wrappers serve a very important purpose. Primitive values don’t have properties or methods, so to access .length
or .toString()
you need an object wrapper around the value. Thankfully, JS will automatically box (wrap) the primitive value to fulfill such accesses.
In general, there’s basically no reason to use the object form directly. It’s better to just let the boxing happen implicitly where necessary. In other words, never do things like new String(“abc”)
, new Number(42)
, etc. — always prefer using the literal primitive values “abc”
and 42
.
There are even gotchas with using the object wrappers directly that you should be aware of if you do choose to ever use them.
For example, consider Boolean wrapped values:
The problem is that you’ve created an object wrapper around the false
value, but objects themselves are “truthy”, so using the object behaves oppositely to using the underlying false value itself, which is quite contrary to normal expectation.
If you have an object wrapper and you want to get the underlying primitive value out, you can use the valueOf()
method.
Let’s look at another example:
Note: by using the build-in natives constructor function we can do not use
new
keyword, they have a “safe” wrapper for this, butnew Date
is an exception.
null
and undefined
don’t have box wrapper.