Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 22

Browser and Third-party APIs

Comments

Variables → containers for reusable values or features. Declared n initialized.


*Scope, var declares it global; let n const declare it block.

Numbers
*toFixed(nº d casas decimais)

*toString()

*Number(varOfStringType) / parseInt(stringNumber[, nº system]) / parseFloat() → parse Strings to


numbers.

Operators → perform tests, do math, join strings together, etc.


*Arithmetic (5 ** 2 -> 25)

*Increment n Decrement (--pre n post++)

*Assignment

*Comparison

*typeof varWhoseTypeWillBeReturned

*Ternary (condition? ifTrueReturned : ifFalseReturned) → for smaller conditions

*Spread (…) → more for arrays/objects

Booleans → more for tests.

Strings
* Escaping char (\)

*length

#None changes the original string, for that, reassign back to it:
*includes(“” [, startPosition]) / startsWith() / endsWith() → check for a substring

*indexOf() / lastIndexOf()→ get occurrence position of a substring. Else returns -1.

*slice(startPosition [, endPosition]) / substring() → extract a substring from it. End position is exclusive.

*toLowerCase() / toUpperCase() → change the string case

*replace(“searchString or regex”, “replacingString”) → update its 1ª occurrence substring.

*replaceAll() → update all substring occurences.

*split(separator) → convert it to array.

Estruturas de Controle
*for currentArrayValueVar of array → more for collections like arrays, sets n maps

*map() / filter() → for collection loops

* for / while(){} / do…while → for collection loops

Arrays
*length

*Access n modify items (position n assignment)

*indexOf() / lastIndexOf()→ get position of an item. Else returns -1.

*unshift() / push(item1, item2, …) → add items to its start n end. Returns the new length.

*shift() / pop() → removes the first n last item. Returns it

*splice(startPosition, elementsNumber[, element1ToAdd, element2ToAddFromThatPosition, ..]) →


removes n adds.

*map(fction) → do sth for every item. Returns new array.

*filter(testFunction) → returns new array with the elements that returned true in test function.

*toString() / join(separator) → convert it to string


Functions → reusable code
*declare (hoisting) n invoke

*default n optional parameters

*anonymous (not hoisted) vs. arrow

*return →return value when it ends running. Useful in the middle of a result

Objects → reusable code. Representing real-world object. They’re the JS core


*properties n methods → object’s vars n functions

*methods can be anonymous or full functions no value:pair

*object literal vs. classes

Object literal

→ to transfer a series of structured, related data items in a request, than individually. Easier than
an array, when you want to identify individual items by name.

*Acces props n meths through dot notation or bracket notation (like associative arrays, accepts not only
literal names but vars too as names)

*this → represents current object, inside it. Useful to manipulate it without mention it literally

*constructor → makes a new object from a function. Initializes, binds this to current object, runs the
fction’s code and returns the new object. Useful if we need many copies of an object, with != values.

Prototype → built-in property of all objects. It has prototype chain. Properties n methods are looked up
in: the object, its prototype then, its prototype’s prototype, etc.

*Object.getPrototypeOf(objNameWhoseProtoWeWant)

*shadowing property → objects’ props n meths “overwrite” its prototype’s


*Object.create(customPrototypeFunction) → to set a prototype of an object, that’s returned

*Object.assign(TargetObj.prototype, customPrototypeFunction) → to set the prototype of a


constructor. To ensure all copies’ll have those features. But assign() is to copy features from obj to obj.

*Object.hasOwn(object, “prop”) / .hasOwnProperty() → to check if a prop is defined in the obj or in its


_proto_ (false).

Classes
*properties, constructor n methods

*constructor called with the Class’s name → new Class(). Omit constructor in the Class if no need for
initializations.

*inheritance → extends. Initialize the superclass’ constructor first, super(args), then its constructor’s.

*polymorphism

*encapsulation → avoid repeat same code n gives security. #privateVarNameOrMethod (to make it
private).

JSON

→ JS has this object. Used to disserialize n serialize. It’s a string

*arrays as JSON

*structure (no meths, “” for prop names n values)

*parse(JSONString) → returns a JS object

*stringify(JSObject) → returns a JSON string


Debugging
*throw Error/EvalError/RangeError/ReferenceError/SyntaxError/TypeError/URIError(“msg here”)

→ Or throw new CustomClassError. Used inside try…catch

*try…catch/finally (.description, .name, .message, etc.)

*debugger;

Asynchronous JavaScript
→ programming technique, cause potentially long running tasks (HTTP request, camera or microphone
access, file upload, etc.) be non-blocking

*event handler

*callback functions → passed to other functions. Callback hell or the pyramid of doom

*Promise → is the object returned by an asynchronous function. Represents the current state of the
operation.

*promise-based APIS

Fetch API

*fetch(requestURL) → returns a promise (fetch object). In pending state.

*then(handlerFunctionWithResponseObjectAsParameter) → it’s called when the request


succeeds. Has a response object with status, url, … properties. In fulfilled state.

*responseObj.json() → to get the response data as JSON. It’s also asynchronous. Returns a
promise n the JSON data. Needs then((data)=>).

*promise chaining → useful when the operation needs consecutive asynchronous function calls.

*catch(handlerFunctionWithErrorObjAsParameter) → Promise’s method to support error


handling. Called when the request fails. Useful in the end of promise chain. In rejected state

*Promise.all([fetch objects here]) → to handler many fetch objects at once all to be fulfilled. As array of
promises.
*Promise.any() → when you need any one of a set of promises to be fulfilled. It is fulfilled if just
one of the array promises fulfills. If none it is rejected.

*async → at the start of a function makes it an async function.

*await → used before a call to a function that returns a promise. This makes the code wait at that
point until the promise is settled. Both make async fctions look like sync code.

*Promise(handlerFunctionWithResolveNRejectFunctionsArgs) constructor → to build a promise-based


APIs.

*workers → enable you to run some tasks in a separate thread of execution

*your main code and your worker code never get direct access to each other's variables

*new Worker(“fileURL”) → returns a worker object.

*postMessage(argument) → to send a message to the worker.

*addEventListener(“message”, (message)=>{ message.data.prop}) → so the worker can listen to


the main code. Data contains the props passed from the main file.

*dedicated worker, shared n service workers

Client-side web APIs


→ APIs are programming features for manipulating different aspects of the browser and
operating system the site is running on, or manipulating data from other web sites or services.

 JavaScript — A high-level scripting language built into browsers that allows you to
implement functionality on web pages/apps. Note that JavaScript is also available in
other programming environments, such as Node.
 Browser APIs — constructs built into the browser that sits on top of the JavaScript
language and allows you to implement functionality more easily.
 Third-party APIs — constructs built into third-party platforms (e.g. Twitter, Facebook)
that allow you to use some of those platform's functionality in your own web pages (for
example, display your latest Tweets on your web page).
 JavaScript libraries — Usually one or more JavaScript files containing custom
functions that you can attach to your web page to speed up or enable writing common
functionality. Examples include jQuery, Mootools and React.
 JavaScript frameworks — The next step up from libraries, JavaScript frameworks (e.g.
Angular and Ember) tend to be packages of HTML, CSS, JavaScript, and other
technologies that you install and then use to write an entire web application from
scratch. The key difference between a library and a framework is "Inversion of Control".
When calling a method from a library, the developer is in control. With a framework, the
control is inverted: the framework calls the developer's code.

*Your code interacts with APIs using one or more JavaScript objects (the entry point), which serve
as containers for the data the API uses (contained in object properties), and the functionality the
API makes available (contained in object methods)

*Manipulating documents

*Fetching data from the server

*Third party APIs

*Drawing graphics

*Video n audio APIs

*client-side storage
*************************************************************************************

*************************************************************************************

*************************************************************************************

*************************************************************************************

*************************************************************************************
Grammar and types
 Basic syntax ( ; to separate commands at the same line. Uses Unicode charset) & comments
(hashbang)
 Declarations
 Variable scope
 Variable hoisting
 Data structures and types (7 primitives: null, undefined, BigInt, Symbol. 1 Object)
 Literals → values n not variables.
 Array literals
 Boolean literals
 Numeric literals
 Object literals
 RegExp literals
 String literals

Control flow and error handling


 if...else
 switch
 try/catch/throw
 Error objects

Loops and iteration


 for
 while
 do...while
 continue
 break
 for...in → iterates over prop names
 for...of → iterates over prop values. Both can be used with destructuring with Object.entries().
 Labeled statements (labelName: statements) → any, so u can use anywhere in your code. Used
in break or continue.

Functions
 Defining functions
 Calling functions (recursive functions those that calls themselves, arguments.callee)
 Function scope
 Closures (nested functions, where inner function’s resources can’t be used by the outer
function). Can be called like(args1)(args2)
 Arguments & parameters (scope chain or name conflict, in name conflict the innermost arg has
precedence). Arguments array-like, very handy when args’re unknown.
*default parameter vs. rest parameter

 Arrow functions

Expressions and operators


 Assignment & Comparisons

*destructuring assignment → makes it possible to extract data from arrays or objects


using a syntax that mirrors the construction of array and object literals.

 Arithmetic operators. Unary operators:

*delete objectName.propName → to delete an obj prop.

*void (expression) → indicates an express with no return

*propNameOrNumber in objectName → returns true or false if the obj’s the prop.

*objectName instanceof objectType → returns true or false if the obj’s of that obj type.

 Bitwise & logical operators
 Conditional (ternary) operator

Numbers and dates


 Number literals
 Number object
 Props:
 MAX_VALUE
 MIN_VALUE
 NaN
 NEGATIVE_INFINITY
 POSITIVE_INFINITY
 EPSILON
 MIN_SAFE_INTEGER
 MAX_SAFE_INTEGER
 Meths:
 .parseFloat() / .parseFloat() → same as global correspondent
 isFinite(value) / isInteger() / isNaN() → more robust than its global /
isSafeInteger()
 toExponential() / toFixed() / toPrecision() → in Number.prototype
 Math object
Method Description
abs() Absolute value
sin(), cos(), tan() Standard trigonometric functions; with the argument in radia
asin(), acos(), atan(), atan2() Inverse trigonometric functions; return values in radians.
sinh(), cosh(), tanh() Hyperbolic functions; argument in hyperbolic angle.
asinh(), acosh(), atanh() Inverse hyperbolic functions; return values in hyperbolic angle
pow(), exp(), expm1(), log(), log10(), log1p(), log2(
Exponential and logarithmic functions.
)
Returns the largest/smallest integer less/greater than or equa
floor(), ceil()
an argument.
Returns the minimum or maximum (respectively) value of a
min(), max()
comma separated list of numbers as arguments.
random() Returns a random number between 0 and 1.
round(), fround(), trunc(), Rounding and truncation functions.
Square root, cube root, Square root of the sum of square
sqrt(), cbrt(), hypot()
arguments.
The sign of a number, indicating whether the number is posit
sign()
negative or zero.
Number of leading zero bits in the 32-bit binary representatio
clz32(),
The result of the C-like 32-bit multiplication of the two
imul()
arguments.

 Date object
 set() → set current obj date
 get() → get current set date
 to() → to return string values from date obj
 parse / UTC methods → to parse date string
 Seconds / minutes
 Hours / Day (of the week)
 Date (day number in the month)
 Months / Year or FullYear

Text formatting
 String literals
 String object
Method Description
Return the character or character code at the specified positio
charAt(), charCodeAt(), codePointAt()
string.
Return the position of specified substring in the string or last
indexOf(), lastIndexOf()
position of specified substring, respectively.
Returns whether or not the string starts, ends or contains a
startsWith(), endsWith(), includes()
specified string.
concat() Combines the text of two strings and returns a new string.
Splits a String object into an array of strings by separating the
split()
string into substrings.
slice() Extracts a section of a string and returns a new string.
Return the specified subset of the string, either by specifying
substring(), substr()
start and end indexes or the start index and a length.
match(), matchAll(), replace(), replaceAll(), search(
Work with regular expressions.
)
toLowerCase(), toUpperCase() Return the string in all lowercase or all uppercase, respectively
Returns the Unicode Normalization Form of the calling string
normalize()
value.
Returns a string consisting of the elements of the object repea
repeat()
the given times.
trim() Trims whitespace from the beginning and end of the string.

 Template literals
 Internationalization
 It’s an API for language sensitive string comparison, number formatting, and date
and time formatting. The entry point is in Intl.
 Regular Expressions
 exec() / test() → RegExp meths
 match(), matchAll(), replace(), replaceAll(), search(), and split() → String meths.

*RegExp literal → useful when the pattern’s known n won’t change. Otherwise, use RegExp
constructor

*simple patterns vs. special chars

* → 0 or more occurrences of the preceding item. /ab*c/

 Assertion type → Assertions include boundaries, and other patterns


(including look-ahead, look-behind, and conditional expressions)
o Boundary-type assertions
^ → matches if char’s at the beginning of the string. /^A/
(Angola)

$ → matches if char’s at the end of the string. /A$/ (This is


A). If the multiline flag is set to true, also matches immediately before a line break
char.

\b → matches if the word character is not followed or


preceded by another word-character. /\bm/, /oon\b/ (in moon). Word boundary.

\B → matches if the previous and next character are of the


same type. /\Bon/ (in noon), /ye\B/ (in possibly yesterday). Non-word boundary.

o x(?=y) → matches x if x’s followed by y in the string. /Jack(?


=Sprat)/ in (JackSprat), /Jack(?=Sprat|Frost)/ Sprat or Frost.
Lookahead assertion
o x(?!y) → /\d+(?!\.)/ matches a number only if it is not followed by a
decimal point. /\d+(?!\.)/.exec(“3.141”) matches "141" but not "3".
Negative lookahead assertion
o (?<=y)x → matches x if x’s preceded by y. /(?<=Tom)Jack/, /(?
<=Tom|Sprat)Jack/. Lookbehind assertion.
o (?<!y)x → /(?<!-)\d+/ matches a number only if it is not preceded
by a minus sign. /(?<!-)\d+/.exec(“3”)

 Character class → Distinguish different types of characters (letters and


digits, etc).
o Character class, [] → Matches any of the characters. You can
specify a range of characters by using a hyphen. [abcd-], [a-z].
o Negated character class, [^] → matches anything that is not in
the brackets. You can specify a range of characters by using a
hyphen.
o . → Matches any single character except line terminators. Inside a
character class, it matches a literal dot. /.y/ in (“my” n “ay”).
o \d → matches any digits. /\d/.exec("B2 is the suite number")
matches “2”
o \D → matches any non-digits. /\d/.exec("B2 is the suite number")
matches “B”
o \w → Matches any alphanumeric character from the basic Latin
alphabet, including the underscore.
o \W →Matches any non-alphanumeric character from the basic
Latin alphabet, including the underscore.
o \s → Matches a single white space character, including space, tab,
form feed, line feed, and other Unicode spaces
o \S → Matches a single non-white space character. /\S\w*/ matches
"foo" in "foo bar".
o \t Matches a horizontal tab.
o \r Matches a carriage return.
o \n Matches a linefeed.
o \v Matches a vertical tab.
o \f Matches a form-feed.
o [\b] Matches a backspace
o \ → treats a character specially or non-specially. [a\*] (matches
“a*”), [\\] (matches “\”)
o Disjunction, x|y → Matches either "x" or "y". \grey|green\

 Groupd and backreferences → Groups group multiple patterns as a whole,


and capturing groups provide extra submatch information when using a
regular expression pattern to match against a string. Backreferences refer
to a previously captured group in the same regular expression.
o

Indexed collections
 Arrays

*sparse an array → make empty holes in it

*multi-dimensional → when an item is also an array

 Typed arrays

Keyed collections
 Map → a key on a map may only occur once.

*keys can be any value (including functions, objects, or any primitive).

 Props:
*size → returns its length
 Meths:
*clear() → removes everything
*delete(‘keyName’) → removes that key/value pair. Returns true if success,
else false in case that ain’t there.
*get(key) → returns its value, else undefined. Any changes to it will reflect
on the map
*has(key) → returns true if any value related, else false.
*keys() → returns a new iterator with all its keys
*values() → returns a new iterator with all its values
*entries() → returns a new iterator with all its [key, value] pair in each
interation.

*set(key, value) → adds or updates an entry. Returns the map obj, so you
can chain the method call.

*forEach(callback[, thisArg]) → callback’s 3 args, key value n map. thisArg’s


passed to callback.

 WeakMap → keys must be object.

*associate private data to an obj

*associate metadata

*caching

 Meths:

*delete(key) / get(key) / has(key) / set(key, value)

 Set → are collections of values.

* a value on a set may only occur once.

*convert between array n set. Repeated items’re deleted in array-to-set conversion.

 Props:
*size
 Meths:
*add(value) → adds the value only if not pre-existing. Returns the set
*clear() / delete(value) / has(value) /
#values() or keys() → returns a new Iterator object with its values.
#entries() → returns a new iterator with all its [value, value] pair in each
interation.
#forEach() → similar to Map’s.

 WeakSet → store weakly held objects in a collection

*values can only be objects


*detect circular reference

 Meths:

*add() / delete() / has()

Working with objects


 Objects and properties

*for…in / Object.keys(obj) / Object.getOwnPropertyNames(obj) → get object properties. Both


return an array

*assign(targetObject, ...sourceObjects) → to copy props/meths to another object.


Returns the targetObject modified. Used for inheritance.

*entries(obj) → returns an array of a given object's own enumerable string-keyed


property key-value pairs. Useful to convert an Object to Map.

*keys(obj) → returns an array of a given object's own enumerable string-keyed


property names.

*values(obj) → returns an array of a given object's own enumerable string-keyed


property values

*freeze(obj) → it cannot be changed or reassigned, writable, configurable… the


highest JS integrity level. Returns the object

*seal(obj) → almost like freeze() but the obj’s still writable since it’s true.

*preventExtensions(obj) → almost like freeze().

*fromEntries(iterable_ArrayOrMap) → transforms a list of [key, value] pairs (or


Map) into an object. Useful to transform objects to Maps. Returns a new object.

*getOwnPropertyDescriptor(obj, prop) → returns an object describing the


configuration of a specific property on a given object (that is, one directly present on an
object and not in the object's prototype chain). The object returned is mutable but
mutating it has no effect on the original property's configuration.

*getOwnPropertyDescriptors(obj) → returns all own property descriptors of a


given object.

*getOwnPropertyNames(obj) → returns an array of all properties (including non-


enumerable properties except for those which use Symbol) found directly in a given
object.

*getOwnPropertySymbols(objWithSymbolProperties) → returns an array of all


symbol properties found directly upon a given object

*getPrototypeOf(obj) → returns the prototype (i.e. the value of the


internal [[Prototype]] property) of the specified object. Can return null

*obj.hasOwn(prop) → static method returns true if the specified object has the


indicated property as its own property. If the property is inherited, or does not exist, the
method returns false. Useful to check if a prop exists. Vs. propName in obj, returns both
own and inherited props.

*obj.hasOwnProperty(prop) → returns a boolean indicating whether the object


has the specified property as its own property (as opposed to inheriting it)

*is(value1, value2) → determines whether two values are the same value.

*isExtensible(obj) → determines if an object is extensible (whether it can have new


properties added to it).

*isFrozen(obj) → determines if an object is frozen.

*isPrototypeOf(protoObj) → checks if an object exists in another object's prototype


chain.

*isSealed(obj) → determines if an object is sealed.

*obj.propertyIsEnumerable(prop) → returns a boolean indicating whether the


specified property is the object's enumerable own property
*toString() / toLocaleString() → returns a string representing the object. Number,
date, array to format it to certain locales.

 Creating objects

*Object.create(prototypeObj[, obj]) → to create an obj with a prototype n not a constructor.


Returns a new object with that proto n props. Used for inheritance.

 Defining methods

*Object.defineProperties(obj, prop1, meth2…) → define or change a prop or meth in an object.


Returns the object

*Data & Accessor descriptors:

# configurable → true or false. True only if the type of this prop may be changed or if
the prop itself may be deleted.

# enumerable → true or false. True only if the prop shows up in an enumeration of the
obj’s props.

*Data descriptors:

# value → the prop’s value, any JS type. Defaults to undefined.

# writable → true or false. True if the value of the current prop is assignable.

*Accessor descriptors:

# get → a fction that serves as the getter of the prop, or undefined if none.

# set → a fction whose return’ll be the prop’s value or undefined.

*Object.defineProperty(obj, prop, descriptor) → define or change a prop or meth in an object.


Returns the object

 Getter and setter

Using classes
 Declaring a class
 Various class features
*static → indicates its static (prop, meths, etc.)

#static initialization block

 Extends and inheritance

*a class can only inherit from one class

 Why classes?

Promises
Overview: Promises

 Guarantees
 Chaining
 Error propagation
 Composition
 Timing

Iterators and generators


Overview: Iterators and generators

● Iterators →object which defines a sequence and potentially a return value upon its termination

*Implements a next(). Which returns

*{value: theCurrentValue, done: booleanValue}

*consumed only as necessary. Can take unlimited number range


● Iterables → objects that define its iteration behavior, such as what values are looped over in a
for...of construct.
*[Symbol.iterator] →key prop that has as value an iterator or generator.

*Arrays, Typed arrays, Set n Maps → are all iterables cuz they've the Symbol.iterator in their
_proto_chain

*it[Symbol.iterator] = function* () {
yield 2;
yield 1;
};

Or

const myIterable = {
*[Symbol.iterator]() {
yield 1;
yield 2;
yield 3;
}
}
→ you can call it in a loop or spread operators

*function* gen() {
yield* ['a', 'b', 'c'];
}

gen().next();
// { value: "a", done: false }

● Generators →allow you to define an iterative algorithm by writing a single function whose
execution is not continuous.

*function* → to build generator function. They return generators

● Generator is a type of iterator. The next() stops at yield.


● The function can be called as many times as desired, and returns a new
Generator each time. Each Generator may only be iterated once.

*The next() method also accepts a value, which can be used to modify the internal state of the
generator. A value passed to next() will be received by yield. The first value is ignored. Useful to reset
the generator, etc.

*Throw(valueToBeThrown) to force a generator to throw an exception. If no catch(err) used,


next() sets done to true.

*Return(value) → returns such value n finishes the generator

Meta programming
The Proxy and Reflect objects allow you to intercept and define custom behavior for
fundamental language operations (e.g. property lookup, assignment, enumeration, function
invocation, etc.). With the help of these two objects you are able to program at the meta level of
JavaScript

● Proxy →The Proxy object enables you to create a proxy for another object, which can intercept
and redefine fundamental operations for that object

*commonly used to log property accesses, validate, format, or sanitize inputs, and so on.

*new Proxy(targetObj, handlerObjWhichDefinesWhatPropsWillBeInterceptedNRedefined)


→make a proxy
● Handlers and traps →methods that provide property access. The same as Objects' methods.
● Revocable Proxy →proxy that can be revoked via the revoke() and switches the proxy off.

*Proxy.revocable(targetObj, handlerObj) →method is used to create a revocable Proxy object.


Afterwards, any operation on the proxy leads to a TypeError.

● Reflect →is a built-in object that provides methods for interceptable JavaScript operations. The
methods are the same as those of the proxy handlers.

*Helps with forwarding default operations from the handler to the target

JavaScript modules
Overview: JavaScript modules

● Exporting →to get access to module features

*export → placed before any items you want exported out of the module

*export { feat1, feat2, featn}; → used at the file bottom to export features.

● Importing → Once you've exported some features out of your module, you need to import
them into your script to be able to use them.

*export { feat1, feat2, featn } from './modules/square.js';

*Once you've imported the features into your script, you can use them just like they were
defined inside the same file

*<script type="module" src="main.js"></script> → to declare a script as a module.

● Default exports → to make it easy to have a default function provided by a module


*export default randomSquare;

● Renaming features → .mjs (clarity n development step) for JS module files, instead of .js (build
step).

*featureName as aliasName →used to avoid name conflicts in import n export syntaxes.

● Aggregating modules →to import each module's features inside a module object.

*import * as Module from './modules/module.js';

● Dynamic module loading → modules are deferred automatically.


*Allows you to call import() as a function, passing it the path to the module as a parameter. It
returns a Promise, which fulfills with a module object giving you access to that object's exports.

*import('./modules/myModule.js')

.then((module) => {

// Do something with the module.

});

In order to maximize the reusability of a module, it is often advised to make the code "isomorphic" —
that is, exhibits the same behavior in every runtime. This is commonly achieved in three ways:

Separate your modules into "core" and "binding". For the "core", focus on pure JavaScript logic like
computing the hash, without any DOM, network, filesystem access, and expose utility functions. For the
"binding" part, you can read from and write to the global context. For example, the "browser binding"
may choose to read the value from an input box, while the "Node binding" may read it from
process.env, but values read from either place will be piped to the same core function and handled in
the same way. The core can be imported in every environment and used in the same way, while only the
binding, which is usually lightweight, needs to be platform-specific.

Detect whether a particular global exists before using it. For example, if you test that typeof window ===
"undefined", you know that you are probably in a Node.js environment, and should not read DOM.

This is preferable if the two branches actually end up with the same behavior ("isomorphic"). If it's
impossible to provide the same functionality, or if doing so involves loading significant amounts of code
while a large part remains unused, better use different "bindings" instead.

Use a polyfill to provide a fallback for missing features. For example, if you want to use the fetch
function, which is only supported in Node.js since v18, you can use a similar API, like the one provided
by node-fetch. You can do so conditionally through dynamic imports:

The globalThis variable is a global object that is available in every environment and is useful if you want
to read or create global variables within modules.

You might also like