JavaScript Cheatsheet (Q&A — Concepts You Need to Know to Pass Tech Interview)

Hanwen Zhang
16 min readOct 29, 2022

--

Share some coding notes I took in the past that helped me understand the concepts, and these are questions you may be asked during interviews.

data type

  • primitive variable stores the values referred to by the value
  • non-primitive object points to a reference (memory location of the value), not the value itself
typeof 42 	//number
typeof "abc" //string
typeof true //boolean
typeof Boolean(1) //boolean
typeof undefined //undefined
typeof null //object (js built-in error)
typeof {"a": 1} //object
typeof [1, 2, 3] //object
typeof function hello(){} //function

false values

false, 0, -0, 0n, “”, null, undefined, and NaN

=, ==, ===

  • = - assignment operator, which sets the variable on the left of the = to the value of the expression that is on its right
  • == - comparison operator, which transforms the operands having the same type before the comparison 2=='2'
  • === - strict equality comparison operator, which returns false for the values which are not of a similar type 2==='2'

coercion — .concat()

It is recommended to use + and += which are better/faster over .concat() for performance reasons.

//automatically convert to string; number + -> concat
console.log(1+"2") //12
console.log(2+"1") //21
console.log(1+2+"1") //31
//no concat, will automatically convert to math operation
console.log(5-"2") //3
console.log(5-"a") //NaN - Not a number, invalid operation, no ascii code in JS

coercion comparison

42 == "42"; // true 
1 == true; // true
var x = "10";
var y = "9";
x < y; // true

dynamic casting

typeof 42 	//number
typeof "abc" //string
typeof Boolean(1) //boolean
let a = 1
console.log(typeof !a) //boolean, check the 2nd value
console.log(!1) //false
let a = 1
console.log(typeof !!a) //true, !! - double negation
let a = 0
console.log(typeof !!a) //false, boolean will be false
!!"" //false, nothing in there
!!" " //true, there is a space, it is not empty
!!{} //true - it is object, empty box but there is something
null == false //false
undefined == false //false
null == undefined //true
null === undefined //false
console.log() //undefined
|| or
&& and
! not
? optional chaining //if not null or undefined, read the value deep within a chain, or check if function exists, return undefined
?? nullish coalescing, nor //replace || for falsy values, only if null or undefined, then use second value
+ numeric representation
console.log(1 || 0) //1
console.log(1 && 0) //0
console.log(1 || 2 || 3) //1 - OR - looking for the first TRUCY value, otherwise return last element
console.log(1 && 2 && 3) //3 - AND - looking for the first FALSY value, if not any, return last element

Loops — Array

const array = [1, 2, 3, 4, 5];for (let i = 0; i < array.length; i++) { 
console.log(array[i]);
}
for (const item of array) {
console.log(item);
}

Loops — Object

const obj = { a: 1, b: 2 };Object.entries(obj).forEach(
([key, value]) => console.log(key, value)
);
Object.keys(obj).forEach(key => {
console.log("key: ", key);
console.log("Value: ", obj[key]);
} );
const keys = Object.keys(obj)
for (const key in obj) {
console.log(key)
}
const values = Object.values(obj)
for (const key in obj) {
console.log(obj[key])
}

`use strict` Mode

It gives you less tolerance for errors, put on top of your program

Error Types

  • ReferenceError occurs when you try to use a variable that doesn't exist at all.
  • TypeError occurs when the variable exists, but the operation you're trying to perform is not appropriate for the type of value it contains
  • SyntaxError occurs when trying to interpret syntactically invalid code.
  • RangeError occurs when a number "out of range" has occurred.
  • Runtime Error is an error that occurs during the running of the program, also known as the exceptions - "bugs"
  • Complier Error occurs before any part of your code runs, the interpreter can not understand at any point in your program,

Error Handling (exception catching)

  • when you do something that may break your program
  • try lets you test a block of code for errors.
  • catch lets you handle the error.
  • throw lets you create custom errors. (execution of the current function will stop, the statements after throw won't be executed, and control will be passed to the first catch block in the call stack. If no catch block exists, the program will terminate.)
  • finally lets you execute code, after trying and catching, regardless of the result.

JavaScript ES6

New Features of ES6

  1. let const vs var
  2. arrow function
  3. template literal
  4. default params
  5. destructuring
  6. spreading (…) /rest (…rest)
  7. promises
  8. class syntax
  9. async/await(ES7)

var and let/const

  • var -issue with value hoisting, put things on the top, scope to the function — old way
  • let/const — not accessible before the line we declare them, scope to the block
  • let: re-assign value; const: no re-assign allowed, we can not change the pointer
console.log(a);    //undefined - variable exist, not able to access to the value
var a = 1;
console.log(b); //ReferenceError - b is not exist, temporal dead zone
let b = 1;

Scoping

for(let i = 0; i < 5; i++){	//let - block scope, let i gives us a new i for each iteration, 
setTimeout(()=>{
console.log(i) //0 1 2 3 4
}, 500);
}
for(var i = 0; i < 5; i++){ //var - function scope
setTimeout(()=>{
console.log(i) //5 5 5 5 5
}, 500);
}

new j created each iteration, which gets a copy of the value of i at this moment

var keeps = [];
for (var i = 0; i < 3; i++) {
let j = i;
keeps[i] = function keepEachJ(){
return j;
};
}
keeps[0](); //0
keeps[1](); //1
keeps[2](); //2

Hoisting

  • Variable hoisting means the JavaScript engine moves the variable declarations to the top of the script.

Temporal Dead Zone

  • accessing a let or const variable before its declaration (within its scope) causes a ReferenceError.
  • between the creation of a variable’s binding and its declaration, is called the temporal dead zone.

Describe Arrow Function

  • simple syntax, less code, if within one line, implicitly returned without the use of the return keyword
  • does not have its own “this” to be referred to as the current object
  • does not need to bind functions
  • use lexical scoping — ‘this’ refers to its current surrounding scope and no further.

The disadvantage of Arrow Function

  • does not have “arguments” which access all the inputs parameters
  • can never be used as constructor functions
  • can never be invoked with the new keyword
  • a prototype property does not exist for an arrow function.
var obj = {
name: "mic",
getName: function(){
return this.name //"this" belongs to the obj that calls the function
}
getName2: () => {
return this.name //arrow function does not have its own "this", "this" here means the Window
}
};
console.log(obj.getName()) //mic
console.log(obj.getName2()) //undefined

default params

const genParam = () => {
console.log("Called");
return 5;
};
function f(x, y = genParam()) {
console.log(x, y);
}
f(1); //1, 5
f(1, 9); //1, 9
f(1, undefined); //1, 5 - no difference from f(1);
f(1, null); //1, null - null considered to be a valid input

destructuring

const obj = { x: 1 };
const { x: otherX } = obj; //re-naming, will be stored in the new name
console.log(otherX) //1
//console.log(x) //no good, referenceError, x is not defined.
//in array, order matters
const arr = [1, 2];
let [z, q] = arr;
console.log(q, z); //2 1
[q, z] = [z, q];
console.log(q, z); //1 2 - reassign the value
//Re-naming
const obj = { x: 1 };
const { x: newVariable } = obj; //just about the syntax, change the name x to newVariable
// const newVariable = obj.x //x as the key to get the value and stores in the variable
console.log(newVariable) //1

spreading (…)

const obj = { x: 1 };
const newObj = { ...obj };
console.log(newObj) //{ x: 1 }
console.log(obj === newObj) //false - shallow clone
const newObj = { ...obj, y: 2 }; // addition
const newObj = { ...obj, x: 2 }; // overwrite
const s = "Hello";
const sArr = [...s];
console.log(sArr) //["H", "e", "l", "l", "o"]
console.log(sArr.length); //5

rest (…rest)

function func(a) {
console.log(a); //1
}
func(1);
function func(a, ...rest) { //rest element must be the last parameter
console.log(rest); //[2, 3, 4, 5, 6, 7]
}
func(1, 2, 3, 4, 5, 6, 7);
function func(a, b, ...rest) {
console.log(rest); //[3, 4, 5, 6, 7]
console.log(arguments[0]); //1 - arguments is for everything in the params, it returns array like object, but does not carry any array methods
}
func(1, 2, 3, 4, 5, 6, 7);

Promise

sync vs async

  • sync code, code that is going to execute right away, one expression at a time.
  • async code, will not get executed right away, but sometime in the future, the next expression runs while the previous finishes up.

Asynchronous JS

  • JS uses callback, promise, and async-await to implement asynchronous patterns.

Promise(event loop, task scheduling)

  • JS is a single-threaded language, that uses a promise to handle async operations, and avoid callback hell which is a chained nested code
  • A Promise is a proxy for a value not necessarily known when the promise is created, which represents WORK that needs to be done at some point.

3 phrases -> pending, fulfilled, rejected

  • chain .then() to do something, and/or .catch() to catch error
  • we can chain more .then(), return a promise, and execute only after the main thread is done
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));let promise = new Promise((resolve , reject) => {
fetch("https://myAPI")
.then((res) => {
// successfully got data
resolve(res);
})
.catch((err) => {
// an error occured
reject(err);
});
});
const promise = new Promise((resolve, reject) => {
//do a thing, possibly async, then...
if(/* everything turned out fine */){
resolve("Stuff worked!")
} else {
reject(Error("It broke!"))
}
});
promise.then((resolve) => { console.log(resolve) }); //Stuff worked!const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
}, 300);
});
myPromise.then((resolve) => {
console.log(resolve);
}).catch((err) => {
console.log(err);
})

Promoise.all([])

  • run promises in parallel, create an array of promises, and then use Promise.all(promisesArray).
  • send all promises, returns a single Promise that resolves to an array of the results of the input promises
  • will reject immediately upon any of the input promises rejecting => if one fails, all fail
  • Promise.racce() works similar as Promoise.all() but return a single value whichever returns the first
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values); //return an array - [3, 42, "foo"] that contains all the value
});

async/await

  • cleaner style handling asynchronous tasks, return a promise, await takes a pause, then returns its result -> must with the async keyword
  • easier for promise chaining (not faster), better for accessing the value in the scope with assigned variable, and the output of function2 is dependent on the output of function1
  • start with async function, replace .then() with await, use try catch for error handling, the async function can be dynamic like MongoDB update/delete endpoints

main thread (console.log) > micro (promise, async/await-pauses) > macro (timeout, interval)

Function

Parameters vs Arguments

function counter(x, y){  //x & y are parameter console.log(x+y);
//do something
}
var a = 10, b = 2;
counter(a, b); //a & b are argument

Callbacks

  • a function passed into another function as an argument, and run after another function has finished.
  • this function will be executed later only after this other function has finished executing
  • JS is a synchronous single-threaded language, but with callback functions, we can perform the async task.
  • great for async calls, handle something after something else has been completed, enforce the order of operation that we want (e.g., Event listeners make use of this)
function greeting(name) {
alert('Hello ' + name);
}
function processUserInput(callback) {
var name = prompt('Please enter your name.');
callback(name);
}
processUserInput(greeting);

First-class function

  • In JS, is called first-class function, aka, first-class citizens.
  • The callback is also a first-class function going by this definition because it is also passed as an argument.
  • The ability of functions to be:
  1. Assigned to variable
  2. Passed as an argument to another function
  3. Returned from another function

Unary Function

  • a function that accepts exactly one argument. It stands for a single argument accepted by a function.
  • const unaryFunction = a => console.log (a + 10); // Add 10 to the given argument and display the value

First Order Function

  • a function that doesn’t accept another function as an argument and doesn’t return a function as its return value.
  • const firstOrder = () => console.log ('I am a first order function!');

Higher Order Function

  • a function that accepts another function as an argument or returns a function as a return value or both.
  • map, reduce, filter, find, etc
const firstOrderFunc = () => console.log ('Hello, I am a First order function');
const higherOrder = (ReturnFirstOrderFunc) => ReturnFirstOrderFunc();
higherOrder(firstOrderFunc);

Currying

  • a nested function that takes multiple arguments one at a time, the last function returns the result based on all the argument
  • convert a function with multiple arguments into several functions of a single argument in sequence.
  • we do not change the functionality of a function, we just change the way it is invoked
  • useful in the context of function composition
  • const addNumber = (a) => (b) => (c) => a+b+c;

Composition

  • a function called in another function
  • You can chain higher-order functions into a composition

Page Redirection

  • window.open('{url}','_blank'); - open in a new window
  • function redirect() { window.location='{URL}' };
  • setTimeout(redirect, 1000);

Popup Boxes

  • alert: window.alert("sometext");
  • prompt: window.prompt("sometext","defaultText");
  • confirm: window.confirm("somtext") ok and cancel -> return boolean

Function Declaration vs Expression

  • Function declarations load before any code is executed
  • Similar to the var statement, function declarations are hoisted to the top of other code.
  • Function expressions load only when the interpreter reaches that line of code.
  • Function expressions aren’t hoisted, which allows them to retain a copy of the local variables from the scope where they were defined.
myF()
function myF(){
console.log("My Function") //it is okay to under the function declaration using keyword function
}
myF()
const myF = function(){
console.log("My Function") //ReferenceError, no good with function expression, can not access function initialization, myF() failed directly
}
myF()
var myF = function(){
console.log("My Function") //TypeError, no good, myF is not a function, var myF = undefined;
//when you try to execute myF, it is good, it is there, but it triggers the function which is undefined, that it breaks the rule.
}

Benefits of Function Expressions:

  • As closures
  • As arguments to other functions
  • As Immediately Invoked Function Expressions (IIFE)

IIFE — immediate invoked function expression

  • runs as soon as it is defined, invoke immediately
  • variables declared in the function expression will not be available outside the function
  • primary purpose: data privacy because any variables declared within the IIFE cannot be accessed by the outside world.

Contains two major parts:

  1. function expression within the Grouping Operator ()
  2. immediately invoke the function ()

Examples

  • (function() { /* */ })()
  • (() => { /* */ })()
for (var i = 1; i <= 3; i++) {		//var makes i stays in the function scope
(function(index) { //inner function gets local copy of outer function arguement
setTimeout(function() { alert(index); }, i * 1000); //having a copy of i in it
})(i); //using a self-invoking function, IIFE, each iteration created a new scope for each iteration
}

Scope

lexical & global

  • Lexical Scope: a variable defined outside a function can be accessible inside another function defined after the variable declaration (Whenever execution context is created, a lexical environment is also created)
  • Global Scope: contains, and is visible in, all other scopes (Global object (in browsers, it is called window) which is referenced by ‘this’.)

block vs function

  • var is function scope.
  • Function scope is within the function, each function creates a new scope
  • let and const are block scope.
  • Block scope is within curly brackets, variables declared inside a { } block cannot be accessed from outside the block

“The Principle of Least Privilege” (POLP)

  • encourages us to use a block (and function) scoping to limit the scope exposure of variables.
  • the least exposure helps keep code understandable and maintainable and helps avoid many scoping pitfalls.

Scoping pitfalls

  • name collision: the identifier comes from one shared scope (like the global scope)
  • unexpected behavior: expose variables/functions whose usage is otherwise private to a piece of the program
  • unintended dependency: expose variables/functions unnecessarily which invites other developers to use and depend on those otherwise private pieces

Shadowing

  • Shadowing: a variable is declared in a certain scope having the same name defined on its outer scope
var a = 99; 
{
let a = 10; //let is block scope
let b = 11;
const c = 200;
console.log(a); //10
}
console.log(a); //99

illegal shadowing

  • Illegal Shadowing: we can shadow var variable by let variable, but cannot shadow let variable by var variable
let a = 10;
{
var a = 20; //SyntaxError: Identifier 'a' has already been declared
}
//var is not scoped to the block it's in, it's scoped to the containing function.
//if there is no containing function, it ends up in the global scope.
//it conflicts with the let a declaration which is also in the global scope.

Closure

what is closure

  • a function returned by another function that still has access to its outer scope variable
  • ability to remember and access scope even if was called from another scope
  • used to enable data privacy, but cons -> may cause memory leak
function makeCounter(){
let count = 0; //private variable for keeping data private and safe
//value by the function will be saved as it will be needed by the inner function, not for garbage collection
return function(){
count++
return count;
};
}
const counterFunc = makeCounter();
console.log(counterFunc()); //1
console.log(counterFunc()); //2
const newFunc = makeCounter(); //a new function, variabel value start over
console.log(newFunc()); //1
console.log(newFunc()); //2

Closure Definition

  • The closure is observed when a function uses variable(s) from outer scope(s) even while running in a scope where those variable(s) wouldn’t be accessible.
  • Closure encapsulates the body of code together with the lexical scope.
  • The closure is most common when working with asynchronous code, such as with callbacks.

Closure Requirements

  • Must be a function involved
  • Must reference at least one variable from an outer scope
  • Must be invoked in a different branch of the scope chain from the variable(s)

Disadvantages of Closures

The closure is associated directly with memory consumption. Hence, it leads to high consumption of memory, if a lot of closures are created, since the allocated memory is not garbage collected till the program expires.

Garbage Collector

It is a program in the browser/JS Engine that is responsible for freeing up the memory which is unutilized.

This

“this” keyword

  • entirely dependent on how it is called
  • refers to the object that the function is a property of.
  • the value will always depend on the object that is invoking the function.

bind vs apply vs call

bind()

  • The bind() method creates a new function used to provide a proper “this” refers to the function
  • it returns a new bound function, does not call the function, but refers to it so that you can execute it later

apply()/call()

  • same, just the different way to put in the parameter: call => comma; apply => array
  • directly triggers itself, call it right now, unlike bind, not yet to call

this in functions

  • “this” behaves differently in arrow functions compared to a regular function.
  • this in regular function, this belongs to function, it binds its own value, like the person.fullName(), "this" refers to the left to the '.'
  • this in arrow function, this DOES NOT belong to arrFunc, it is outside of the function, arrow functions don't bind their own this value

this examples

//1. this IN method, this -> object owner
const person = {
firstName: 'Viggo',
lastName: 'Mortensen',
fullName: function () {
return `${this.firstName} ${this.lastName}` //just like ${person.firstName} ${person.lastName}, this -> object owner
},

// fullName: () => { //"this" has nothing to do with the scope where the function is created, it has to do with how the function is executed
// console.log(this); // "this" refers to Window, if we do person.fullName() which means Window.fullName() - it will be undefined
// return `${this.firstName} ${this.lastName}`
// }, //when we are using arrow function, "this" will be jumping out to the original block which will be global scope

shoutName: function () {
setTimeout(() => {
//keyword 'this' in arrow functions refers to the value of 'this' when the function is created
console.log(this); //"this" refers to the person Object
console.log(this.fullName())
}, 3000)

// shoutName: function () {
// setTimeout(function () => { //we have to use arrow function here instead
// console.log(this); // "this" refers to Window object here
// console.log(this.fullName()) //this.fullName is not a function - it has to do with the execution context
// }, 3000)
}
}
person.fullName() //"this" refers to the left to the '.' here is the person
//2. this IN function, this -> global on browser -> Window
function a() {
console.log(this) //Window, this -> global
}
a() //Window
console.log(this) //Window
//2.1 this IN function, strick mode, this -> undefined
function a() {
"use strict"
console.log(this)
}
a(); //undefined
//3. this IN event, this -> HTML element that received the event
<button onClick="this.style.display"="none">
click to remove me!
</button>

DOM

Critical Rendering Path — steps the browser makes to paint the page.

  • DOM — browser compiles the Document Object Model;
  • CSSOM — browser compiles the CSS Object Model;
  • Render Tree — browser combines DOM and CSSOM to render the tree;
  • Layout — browser computes the size and position of each of the objects;
  • Paint — browser converts the tree into the pixels on the screen;

Optimize CRP

  • Optimize the order of sources — load critical resources as soon as possible;
  • Minimize the number of sources — reduce the number, load async;

DOM Elements

  • selector: getElementById, getElementByTagName, querySelector, querySelectorAll;
  • navigation: children (elements): childNodes (nodes), firstElementChild, lastElementChild, parentElement, previousElementSibling, nextElementSibling;
  • attributes: classList, clientHeight, clientWidth, childElementCount, setAttribute(attrName, value) removeAttribute(attrName) removeAttribute(attrName) ;

DOM Manipulation

  • Adding Elements: body.append("Hello World"); body.append(div); .appendChild(div);
  • Creating Elements: document.createElement("div");
  • Modifying Element Text: div.innerText="Hello World" (how HTML works and looks at CSS like invisible); div.textContent="Hello World" (exact text content copy pasted in HTML);
  • Modifying Element HTML: div.innerHTML="<strong>Hello World</strong>";
  • Removing Elements: div.remove(); .removeChild(span);
  • Modifying Element Attributes: span.getAttribute("id"); span.setAttribute("title", "Hello"); span.removeAttribute("id");
  • Modifying Data Attributes: console.log(span.dataset.test); span.dataset.newName="hi";
  • Modifying Element Classes: span.classList.add("new-class"); span.classList.remove("hi"); span.classList.toggle("hi2", false);
  • Modifying Element Style: span.style.backgroundColor="red";
  • Select: document.querySelector("div");
  • Make Interactive: btn.addEventListener();
  • Change CSS: Style Property

Event

  • defined action or occurrence
  • we can write code that runs specifically when one of these actions or occurrences happen

Event Handling

  • Events are triggered by the user, the browser, or something else to make changes to HTML, CSS, and JavaScript
  • Detect and Respond to an event using JavaScript
  • identify a DOM node to monitor
  • identify the event you want to respond to
  • create a function to run when the event is triggered

addEventListener()

  • element.addEventListener(event, function, useCapture)
  • addEventListener() method attaches an event handler to the specified element, anonymous functions are not supported in the AddEventListener call, which will cause an error.
  • removeEventListener() method to remove an event handler that has been attached to the addEventListener() method.
  • event: A String that specifies the name of the event like “click”, “mouseover”, “keyup”
  • function: Specifies the function to run when the event occurs
  • useCapture: Optional. A Boolean specifies whether the event should be executed in the capturing (true) or bubbling phase (false).

DOMContentLoaded

  • run the callback function when DOM loads
document.addEventListener('DOMContentLoaded', (event) => {
console.log('DOM fully loaded and parsed');
});

Event.preventDefault()

  • prevent the browser from executing the default action of the selected element.
  • Clicking on a “Submit” button, prevent it from submitting a form
  • Clicking on a link, prevent the link from following the URL

Event.stopPropagation()

  • prevents further propagation of the current event in the capturing and bubbling phases.
  • By default, events are bubbled. This propagation of event is expensive and we can stop it by calling, the .stopPropagation() method.

Event Propagation

  • like a deeper ocean goes to the layer one by one travels through the DOM tree to arrive at its target and what happens to it afterward

Three phases in order are:

  1. the event capturing phase - top to the bottom - outermost to inner - click outer which will trigger the inner one.
  2. the target phase - all the listeners registered on the event target will be invoked
  3. the event bubbling phase - bottom to the top - innermost to outer - click the inner one, the outer one will also be clicked

Event Delegation

  • Allow you to avoid adding event listeners to specific nodes; instead, the event listener is added to one parent.
  • Instead of attaching the event listeners directly to the buttons, you delegate listening to the parent <div id="buttons">.
  • When a button is clicked, the listener of the parent element analyzes the bubbling event and catches on a matched child element (recall the event propagation).

PROS of event delegation:

  1. Improves Memory
  2. Write less code
  3. DOM manipulation

CONS of event delegation:

  1. All events are not bubbled up, like, blur, resize, etc.
Photo by Gabriel Heinzer on Unsplash

--

--

Hanwen Zhang

Full-Stack Software Engineer at a Healthcare Tech Company | Document My Coding Journey | Improve My Knowledge | Share Coding Concepts in a Simple Way

Recommended from Medium

Lists

See more recommendations