Notes on Axel Rauschmayer's JavaScript for Impatient Programmers
May 21, 2023
These are my notes from Javascript for impatient programmers. I highly recommend you read through the book for a better understanding of the concepts. However, if you are already familiar with JS this could be a great way resource to revise essential things.
III - Variables and values
Variables and assignment
let
Variables declared using let are blocked scope and mutable.
{
let i;
i = 0;
console.log(i) //0
}
console.log(i) //ReferenceError
const
Variables declared using const are blocked scoped and immutable. They have to be declared and uninitialized at the same point.
{
const i = 0;
i = 1; //TypeError: Assignment of const variable.
console.log(i) //0
}
console.log(i) //Reference error
When are saying that variables declared via const are immutable we mean the binding between the variable name and its value. The value itself could be mutable.
Here we depict that the connection between i
and {}
is constant and cannot be changed but we can add a new property to the {}
.
Stactic vs Dyanmic
- Static means something is related to the source code and can be determined without executing code.
- Dynamic means at runtime.
Global variable and global object
All the scope in javascript can be imagined in a tree form. The outermost scope or root node is the global scope of the environment.
The variables of the global scope are called global variables and are accessible everywhere.
There are two types of global variables.
- Global declarative variables.
Normal variables are declared using
let
,const
orclass
declarations. - Global object variables.
Variables are declared using
var
orfunction
declarations.
globalThis is used to access global object variables. The reason why it got its name is that it is equal to this
in the global scope.
//Global scope
const declarativeVariables = 0;
var objectVariables = 23;
console.log(declarativeVariables) //0
console.log(objectVariables) //23
console.log(globalThis.declarativeVariables)//undefined
console.log(globalThis.objectVariables) //23
Declarations: scope and activation
Declaration scope is the area where a variable or entity can be seen. Variables that are blocked scope have their declaration scope between the {
and }
they enclosed.
But, their activation is somewhere else. The activation is the line where we can access the variable or entity without getting any errors.
{
console.log(sum) //ReferenceError
const sum = 0;
}
Here we are trying to access a variable in its scope but the variable is not activated yet. const
, let
and class
declarations behave in this particular way. The zone between the scope and activation of the entity is called Temporal Dead Zone (TDZ).
The reason why class
declarations also have TDZ is following
class Name extends <expression>{
}
the expression part could evolve into anything and it is better to start its activation at the same place where it is written to not make things confusing.
Whereas, the variables declared with var
are function scoped and do not have TDZ. In the case of variables declared with var
will return undefined
when accessed before their initializations.
The same goes with function
, you could write the function declaration at the bottom and make a function call at the top of the file.
However, there is a caveat. function
declared with let
or const
keywords have TDZ and cannot be accessed before their declarations.
onetwothree() //ReferenceError
const onetwothree = () => {return 123;}
Closures
Closures are functions that have a connection with variables that exist at their "birth place".
function increment(value){
return (num) => {
return num+value;
}
}
const incrementFive = increment(5);
console.log(incrementFive(1)); //6
Static scoping is supported via closures in JS. Technically every function is a closure.
Use cases of closures
- They are implementation of static scoping and help to provide context data to callbacks.
- To store state to persist across function calls.
Values
What is a type?
Type is a set of values.
For example, type boolean
consist of {true, false}
. Only two values.
Similarly, string
and number
have infinitely many values.
The types in JS are:
- null
- undefined
- boolean
- string
- number
- bigint
- symbol
- object
Primitive values are variables of the types null, undefined, string, number, bigint, symbol and boolean and all other values are objects.
Primitive values are always passed and compared by values. Object values are always passed and compared by reference.
Two common ways of creating an object:
- Object literal
const obj = { first : 'saumya' }
- Array literal
const arr = ['saumya']
typeof and instanceof
- typeof is used to check the type of a value. Returns a string.
- instanceof determines which class created a given value. Returns
true
orfalse
.
Rule of thumb: typeof is used for primitive types and instanceof is used for Objects.
x | typeof x |
---|---|
undefined | 'undefined' |
null | 'object' |
string | 'string' |
boolean | 'boolean' |
bigint | 'bigint' |
number | 'number' |
function | 'function' |
All other objects | 'object' |
({}) instanceof Object //true
([]) instanceof Array //true
123 instanceof Number //false
Use Object(value)
to convert a value from a primitive to an object type.
x | Object(x) |
---|---|
undefined | {} |
null | {} |
string | new String(x) |
boolean | new Boolean(x) |
bigint | An instance of BigInt |
number | new Number(x) |
symbol | An instance of Symbol |
object | x |
Coercion
When we perform an operation, the operator needs the operands in a specific type. If the operands are not in the desired types, they are tried to convert into the desired type. Most of the time people don't bother to understand the significance of operand type and raise questions about the unpredictability of JS.
For example
'1' x '4'
will result in 4
. Because the x
operator will convert its operand to numbers.
Operators
Loose equality ( == )
- It coerces its operands to a primitives type if the other operand is a primitive type.
- If both operands are objects, they are only equal if the objects are the same.
undefined == null //true
Strict Equality ( === )
- It doesn't coerce its operands.
undefined === null //false
NaN === NaN //false
Strictest : Object.is(x,y)
Object.is(123,123) //true
Object.is(NaN,NaN) //true
Nullish Coalescing operator ( ?? )
If the first operand is either null
or undefined
and returns the second operand as a fallback.
a ?? b
a !== undefined && a!== null ? a : b
Comma Operator
Evaluate both expressions and return the second one.
2+2,4+1 //5
Void operator
Evaluates its operand and return undefined
void(3+1) //undefined