This is a working document for all my notes on Javascript. Mostly it covers the niche and weird parts of the language.
Most of what follows is a condensed version of javascript.info.
use strictThis directive provides a way to opt-in to modern Javascript (post-ES5). It can be enabled at the script level or at the function level and must be the first statement except for comments.
Adding this directive isn’t strictly necessary for code that uses modern features such as modules and classes.
var, let and constlet and const create block-scoped variables and constants respectively.
var, similar to let, is either function-scoped or global-scoped. It should be avoided in modern code.
{
var a = 1; // global-scoped
let b = 1; // block-scoped
}
console.log(a); // 1
console.log(b); // ReferenceError: b is not defined
var declarations are hoisted to the top of the scope but are not initialised. They can also be redeclared unlike let and const.
console.log(a); // undefined
var a = 1;
console.log(a); // 1
var also becomes a member of the global object (window in the browser).
var a = 1;
console.log(window.a); // 1
Most people recommend using
constoverletunless reassignment is absolutely necessary. Most linters will include a rule to preferconstby default. Dan Abramov wrote an interesting article on the topic. I personally don’t care too much and lately tend towards usinglet.
Javascript has the following primative data types: number, string, boolean, null, undefined, symbol and bigint.
Numbers can represent both integers and floating point numbers. There are 3 special values: Infinity, -Infinity and NaN.
undefined represents a variable that has been declared but not assigned a value. null represents a deliberate absence of any object value.
The typeof operator can be used to get a string representation of the type of a variable. There are a few oddities to be aware of:
typeof null // "object"
typeof function() {} // "function"
Here null is not an object, while functions are actually objects. Both of these are kept in the language for backwards compatibility.
Data types can be cast into numbers using the Number() function or the unary + operator.
Number("1"); // 1
Number(""); // 0
Number("hello"); // NaN
Number(true); // 1
Number(false); // 0
Number(null); // 0
Number(undefined); // NaN
Number(Symbol("symbol")); // TypeError: Cannot convert a Symbol value to a number
In Javascript we use === for strict equality (same type and value).
Equality and comparisons are implemented differently leading to the following peculiarities:
null == 0; // false
null >= 0; // true
undefined == 0; // false
undefined >= 0; // false
Comparisons cast values to numbers e.g. null becomes 0 and undefined becomes NaN. However, equality is treated differently such that null == undefined is true.
Functions in Javascript are values, they are actually objects and can be passed around like any other value.
Function arguments are mutable.
function f(a) {
a = 2; // Works!
}
Function declarations are hoisted to the top of the scope whereas function expressions are not.
f(); // Works!
g(); // ReferenceError: g is not a function
h(); // ReferenceError: h is not a function
function f() {}
let g = function() {};
let h = () => {};
The in operator can be used to check if a property exists on an object. for ... in can be used to iterate over all string keys in an object. Number keys are ordered.
const obj = {
a: 1,
b: 2,
c: 3,
};
for (const key in obj) {
console.log(key);
}
Objects are passed by reference. Object equality determines if two objects point to the same reference.
We can clone objects in a few ways: shallow copy via Object.assign() or the spread operator and deep copy via structuredClone().
Note that function properties are not supported by
structuredClone(). Trying to clone an object with a function property will throw an error.
Symbols are unique primative values that can be used as object keys. Mostly used for object internals as they can’t be accessed without the symbol itself.
const id = Symbol("id");
const obj = {
[id]: "123",
};
console.log(obj[id]); // "123"
There also exists a global symbol registry that can be used to create symbols that are globally unique.
// a.js
const id = Symbol.for("id");
// b.js
const id2 = Symbol.for("id");
console.log(id === id2); // true
this keywordThe this keyword is bound to the object that the function is called on. It does not exist when using arrow functions.
const o = {
x: 10,
f: function() {
console.log(this.x); // 10
},
g: () => {
console.log(this.x); // undefined
}
};
o.f(); // 10
o.g(); // undefined
We can use the function bind() method to create a new function where this is bound to a specific value we provide.
function f() {
console.log(this);
}
f(); // undefined
f.bind("Hello")(); // "Hello"
We can also use the call() and apply() methods to call a function with a specific this value.
We can use function constructors to create multiple similar objects. We use the new keyword which implicitly sets this to a new object and returns this.
function Person(name) {
// this = {}
this.name = name;
// return this
}
const p1 = new Person("John");
const p2 = new Person("Jane");
console.log(p1.name); // "John"
console.log(p2.name); // "Jane"
We can use new.target inside the constructor function to determine if it was called with the new keyword. If called with the new keyword, new.target will be the constructor function. If called without the new keyword, new.target will be undefined.
Note that when using the new keyword, primative returns are ignored and object returns replace the implicit return of this.
function Person(name) {
console.log(new.target);
return 10;
}
Person("John"); // Logs: undefined. Returns 10.
new Person("John"); // Logs: [Function: Person]. Returns the new object.
Javascript uses a generational, incremental mark-and-sweep garbage collection algorithm.
Propellant Open Source
Modern task management.Vox Open Source
Simple, lightweight customer feedback tool.Hype Open Source
Open-source toolkit for building waitlists.Starter Open Source
TanStack-based starter kit for building web apps at speed.Quadratic Open Source
Feedback widget built for Linear.