Data types
- Primitive data types are passed by value, while non-primitive data types are passed by reference
- To know the type of a JavaScript variable, we can use the typeof operator.
Example
typeof "John Doe"; // Returns "string"
typeof 3.14; // Returns "number"
typeof true; // Returns "boolean"
typeof 234567890123456789012345678901234567890n; // Returns bigint
typeof undefined; // Returns "undefined"
typeof null; // Returns "object" (kind of a bug in JavaScript)
typeof Symbol("symbol"); // Returns SymbolPrimitive types
- String
- To use the same quotation marks inside a string and to delimit a string,
use backslashes for each quotation inside the string, e.g.
"This is Joe's \"favorite\" string; - Write strings in multiple lines using backslashes
- To use the same quotation marks inside a string and to delimit a string,
use backslashes for each quotation inside the string, e.g.
- Number
- BigInt
- Boolean
- Undefined: when a variable is declared but not assigned, variables that haven’t been assigned a value
- Null: non-existent or invalid value or empty value
- Symbol: introduced in ES6 version. It is used to to be an anonymous and unique value
Non-primitive types (objects)
-
If the key contains spaces or special characters, you need to use square braces notation for assignment
bird["where it lives"] = "forest"; // this notation is useful for using variables to access properties // var query = "numPockets"; // backpack[query] -
Delete keys with
.deletekeyworddelete bird.color; -
Objects can be copied in multiple ways
animal2 = Object.assign({}, animal); animal2 = { ...animal }; animal2 = JSON.parse(JSON.stringify(animal)); -
Check if Object has something:
myString.hasOwnProperty("length"); -
Check type
typeof myString; -
Check for number
Number.isNaN(12); // false -
Check for
nulltypeof null; // object var thing = null; thing === null; // true
null vs undefined vs undeclared
| Trait | null | undefined | Undeclared |
|---|---|---|---|
| Meaning | Explicitly set by the developer to indicate that a variable has no value | Variable has been declared but not assigned a value | Variable has not been declared at all |
| Type | object | undefined | Throws a ReferenceError |
| Equality Comparison | null == undefined is true | undefined == null is true | Throws a ReferenceError |
Undeclared
Undeclared variables are created when you assign a value to an identifier
that is not previously created using var, let or const. Undeclared
variables will be defined globally, outside of the current scope. In strict
mode, a ReferenceError will be thrown when you try to assign to an undeclared
variable. Undeclared variables are bad just like how global variables are bad.
Avoid them at all cost! To check for them, wrap its usage in a try/catch
block.
Example
function foo() {
x = 1; // Throws a ReferenceError in strict mode
}
foo();
console.log(x); // 1undefined
A variable that is undefined is a variable that has been declared, but not
assigned a value. It is of type undefined. If a function does not return any
value as the result of executing it is assigned to a variable, the variable also
has the value of undefined. To check for it, compare using the strict equality
(===) operator or typeof which will give the 'undefined' string. Note that
you should not be using the loose equality operator (==) to check, as it will
also return true if the value is null.
Example
let foo;
console.log(foo); // undefined
console.log(foo === undefined); // true
console.log(typeof foo === "undefined"); // true
console.log(foo == null); // true. Wrong, don't use this to check if a value is undefined!
function bar() {} // Returns undefined if there is nothing returned.
let baz = bar();
console.log(baz); // undefinednull
A variable that is null will have been explicitly assigned to the null
value. It represents no value and is different from undefined in the sense
that it has been explicitly assigned. To check for null, simply compare using
the strict equality operator. Note that like the above, you should not be using
the loose equality operator (==) to check, as it will also return true if
the value is undefined.
Example
const foo = null;
console.log(foo === null); // true
console.log(typeof foo === "object"); // true
console.log(foo == undefined); // true. Wrong, don't use this to check if a value is null!Notes
- As a good habit, never leave your variables undeclared or unassigned.
Explicitly assign
nullto them after declaring if you don’t intend to use them yet. - Always explicitly declare variables before using them to prevent errors.
- Using some static analysis tooling in your workflow (e.g. ESLint, TypeScript Compiler), will enable checks that you are not referencing undeclared variables.
Expression vs statement
There are two main syntactic categories in JavaScript: expressions and statements. A third one is both together, referred to as an expression statement. They are roughly summarized as:
- Expression: produces a value
- Statement: performs an action
- Expression statement: produces a value and performs an action
A general rule of thumb:
If you can print it or assign it to a variable, it’s an expression. If you can’t, it’s a statement.
Statements
let x = 0;
function declaration() {}
if (true) {
}Statements appear as instructions that do something but don’t produce values.
// Assign `x` to the absolute value of `y`.
var x;
if (y >= 0) {
x = y;
} else {
x = -y;
}The only expression in the above code is y >= 0 which produces a value, either
true or false. A value is not produced by other parts of the code.
Expressions
Expressions produce a value. They can be passed around to functions because the interpreter replaces them with the value they resolve to.
5 + 5; // => 10
lastCharacter("input"); // => "t"
true === true; // => trueExpression statements
There is an equivalent version of the set of statements used before as an expression using the conditional operator:
// Assign `x` as the absolute value of `y`.
var x = y >= 0 ? y : -y;This is both an expression and a statement, because we are declaring a variable
x (statement) as an evaluation (expression).
Implicit Type Coercion
Conversion of value from one data type to another. It takes place when the operands of an expression are of different data types.
String coercion
String coercion takes place while using the ‘ + ‘ operator. When a number is added to a string, the number type is always converted to the string type.
var x = 3;
var y = "3";
x + y; // Returns "33"Type coercion also takes place when using the ‘ - ‘ operator, but the difference while using ‘ - ‘ operator is that, a string is converted to a number and then subtraction takes place.
var x = 3;
Var y = "3";
x - y // Returns 0Boolean Coercion
-
Truthy values are those which will be converted (coerced) to true. Falsy values are those which will be converted to false.
-
All values except
- false
- 0
- 0n
- -0
- “”
- null
- undefined
- NaN
are truthy values
Logical Operators
- Logical operators in JavaScript, unlike operators in other programming languages, do not return true or false. They always return one of the operands.
- OR ( || ) operator: If the first value is truthy, then the first value is returned. Otherwise, the second value is returned.
- AND ( && ) operator: If both the values are truthy, always the second value is returned. If the first value is falsy then the first value is returned or if the second value is falsy then the second value is returned.
var x = 220;
var y = "Hello";
var z = undefined;
x || y; // returns 220 since the first value is truthy
x || z; // returns 220 since the first value is truthy
x && y; // returns "Hello" since both the values are truthy
y && z; // returns undefined since the second value is falsy
if (x && y) {
console.log("Code runs"); // runs because x && y returns "Hello" (truthy)
}
if (x || z) {
console.log("Code runs"); // runs because x || y returns 220 (truthy)
}Equality Coercion
The == operator compares values and not types.
var a = 12;
var b = "12";
a == b; // Returns true because both 'a' and 'b' are converted to the same type
var a = 226;
var b = "226";
a === b; // Returns false because coercion does not take placeEquality operators
-
==is the abstract equality operator while===is the strict equality operator. The==operator will compare for equality after doing any necessary type conversions. The===operator will not do type conversion, so if two values are not the same type===will simply returnfalse. -
Use
===when you want to ensure both the value and the type are the same, which is the safer and more predictable choice in most cases. -
ESLint’s
eqeqeqrule enforces the use of strict equality operators===and!==and even provides an option to always enforce strict equality except when comparing with thenullliteral. -
There’s one final value-comparison operation within JavaScript, that is the
Object.is()static method. The only difference betweenObject.is()and===is how they treat of signed zeros andNaNvalues. The===operator (and the==operator) treats the number values-0and+0as equal, but treatsNaNas not equal to each other. -
Rules:
Same Type Comparison
- If both operands are the same type, use strict equality (
===) comparison 1 == 1→true"hello" == "hello"→trueNaN == NaN→false(special case)null == null→trueundefined == undefined→true
null and undefined
null == undefined→true(only case where they equal something other than themselves)null == 0→falseundefined == 0→falsenull == false→falseundefined == false→false
Number and BigInt
- Compare numerically if the Number is a safe integer with no fractional part
1n == 1→true1n == 1.0→true1n == 1.1→false9007199254740993n == 9007199254740993→false(precision loss in Number)
String and Number
- Convert string to number, then compare
"42" == 42→true"" == 0→true(empty string converts to 0)" " == 0→true(whitespace-only string converts to 0)"hello" == 0→false(“hello” converts to NaN)
Boolean Conversion
- Convert boolean to number first (
true→ 1,false→ 0), then restart comparison true == 1→truefalse == 0→truetrue == "1"→true(true becomes 1, then 1 == “1”)false == ""→true(false becomes 0, then 0 == "")
Object to Primitive
- Convert object to primitive using ToPrimitive operation (
valueOf()thentoString()) [] == ""→true([] converts to "")[42] == "42"→true([42] converts to “42”)[42] == 42→true([42] converts to “42”, then “42” == 42){} == "[object Object]"→true({} converts to “[object Object]”)[1,2,3] == "1,2,3"→true
Symbol Comparison
- Symbols never equal anything except identical symbols (using
===) - No type conversion occurs with symbols
Symbol("x") == "x"→falseSymbol("x") == Symbol("x")→false(different symbol instances)
Default Case
- If no conversion rule applies, return
false
Conversion Order
- Check if same type → use
=== - Check
null/undefinedspecial case - Check Number ↔ BigInt
- Check String ↔ Number
- If Boolean involved → convert to Number and restart
- If Object involved → convert to Primitive and restart
- If Symbol involved → return
false(no conversion) - Otherwise → return
false
Common Gotchas
[] == ![]→true([] converts to "", ![] converts to false then 0, so "" == 0)[] == 0→true[0] == 0→true"0" == [0]→true" \t\r\n " == 0→true(whitespace converts to 0)({}) == false→false(“[object Object]” != 0)
- If both operands are the same type, use strict equality (
Dynamically typed language
- JavaScript is a dynamically typed language, the type of a variable is checked during run-time, in contrast to a statically typed language, where the variable is checked during compile time
- Since JavaScript is a loosely (dynamically) typed language, variables in JavaScript are not associated with any type. A variable can hold the value of any data type.
- For example, a variable that is assigned a number type can be converted to a string type.
NaN
- NaN property type represents the Not a Number value. It indicates that it is not a legal number.
- typeof of NaN will return a Number.
- To check if a value is NaN, we use isNan() function
isNaN("Hello"); // Returns true
isNaN(345); // Returns false
isNaN("1"); // Returns false, since '1' is converted to Number type which results in 0 ( a number)
isNaN(true); // Returns false, since true converted to Number type results in 1 ( a number)
isNaN(false); // Returns false
isNaN(undefined); // Returns truePassed by value and passed by reference
-
In JavaScript, primitive data types are passed by value and non-primitive data types are passed by reference
-
In this example, the assign operator knows that the value assigned to y is a primitive type (number type in this case), so when the second line code executes, where the value of y is assigned to z, the assign operator takes the value of y (234) and allocates a new space in the memory and returns the address. Therefore, variable z is not pointing to the location of variable y, instead, it is pointing to a new location in the memory.
var y = 234; var z = y; -
Primitive data types when passed to another variable, are passed by value. Instead of just assigning the same address to another variable, the value is passed and new space of memory is created.
var y = #8454; // y pointing to address of the value 234 var z = y; var z = #5411; // z pointing to a completely new address of the value 234 // Changing the value of y y = 23; console.log(z); // Returns 234, since z points to a new address in the memory so changes in y will not affect z -
The assign operator directly passes the location of the variable obj to the variable obj2. In other words, the reference of the variable obj is passed to the variable obj2.
var obj = { name: "Vivek", surname: "Bisht" }; var obj2 = obj; -
While passing non-primitive data types, the assigned operator directly passes the address (reference).
var obj = #8711; // obj pointing to address of { name: "Vivek", surname: "Bisht" } var obj2 = obj; var obj2 = #8711; // obj2 pointing to the same address // changing the value of obj1 obj.name = "Akki"; console.log(obj2); // Returns {name:"Akki", surname:"Bisht"} since both the variables are pointing to the same address.