Modern JavaScript Essentials

This article consists of notes taken in a practical introduction to the native modern JavaScript language by Samer Buna. This introduction covered topics such as objects, functions, scopes, promises, modules, and APIs.

. Variables are different in terms of scope
. Scope can be function or block based. They can be nested. Any line of code has scopes
. There’s always a root scope
. We could use Node, the console, JSFiddle or JS Complete Playground. The advantage in the last two allow for “multiplayer” but jsPlayground requires you to run the code / it’s not real time.
. Never use var (it wasn’t removed due to backward compatibility)
. Strings and numbers are immutable. Arrays and objects are mutable. So, if we have an object, even though we’re using a const, we can change the value
. function printArgs(a,b) {} is like defining a and b with let
. “this” and the arguments keyword are implicit in functions
. arguments resemble an array (but we shouldn’t really use it) even though we can access it with arguments[0], arguments[1] but won’t be able to use arguments.forEach()
Note: we could trick the system like this
[], function (e) {

. Functions are first class. They are basically objects and we can pass it around
. Higher Order Functions (HOF) – a function that returns a function
. forEach is a function to an array, so we need the reference first
. As alternative to arguments, we can use destructuring and the rest/spread syntax
function printArgs(a, ...args) {
args.forEach(function(e) { display(e) }};
printArgs(10, 20, 30, 40);

In this case, ...args needs to come last.
. In a regular function, the “this” keyword is the calling environment. In arrow functions, it’s the defining / execution environment. In particular,
function rf() {
console.log('In RF', this); // Calling environment - it would print 42
const af = () => {
console.log('In AF', this); // defininig environment - it would print an Object

. If you’re interested in going deep in JavaScript – You Don’t Know JavaScript Yet – 2nd edition
. Everything in JS is an object, including functions. We can put properties into functions, for instance
const rf = function() {

rf.answer = 42;

const aliasRF = rf;

aliasRF.answer = 37;

rf(); // We'll get 37

. A closure is created anytime you define a function
. Declaration phase is hoisted to the top of the function. What if we call the function again?
function printA() {
//var a;
var a = 1;
// a = 1;

It’ll print undefined (and not give ReferenceError) because they share different scopes. Scope is created when we execute the function
. A closure gives you read and write access
. Closures are created when you define a function
let a = 1;

const closure1 = function() {
a = 2

a = 3;

const closure2 = function() {

closure1(); // 3
closure2(); // 2

. Attention to declare -> define -> execute
. This example makes it clearer scope and closures
let a = 1;

function A() {
let a = 2;

// closure B
function B() {


this will print 1.
. The Call Stack (TCS) – you get only one / JS is single-thread (if you block it, even browser scrolling will be blocked so we don’t want to block it). Stack: last-in, first-out (LIFO). This differs from the Queue (first-in, first-out (FIFO)).
. Everytime we call a function, we put it in TCS. Everytime we return it, we remove it from TCS
. The Event Loop (When TCS is empty and there are events in the queue)
. What the heck is the event loop anyway?


. In async we can use browser’s thread instead of JS’s singe-thread. For instance,
const fp = fetch('');

console.log(fp); // Promise pending

setTimeout(() => {
console.log(fp); // Promise fulfilled
}, 1000)

As a Promise we’d do then.catch(). Yet, if we can consume the promise using the await keyword (we’ll need to wrap it in a function with async) and wrap it in a try/catch,
async function main() {
try {
const fp = await fetch('');
} catch (err) {
// err (network to be slow, offline)

Related Stories