There are tons of concepts related to JavaScript which you’ve been encountered over your careers, but trying to cover all of them before interviews seems intimidating and might devastate your confidence in tight schedule.
The first important thing is being able to code comfortably with JavaScript fundamentals including basic concepts, syntax, built-in objects, data types, and operators. MDN is probably the best place to learn it, practicing Data Structures & Algorithms with JavaScript is the ideal combination.
The second important thing is being able to explain some programming concepts related to JavaScript which are often advanced and confusing. Experienced engineers sometimes have difficulties explaining those topics even though they’ve been working with them for ages. Interviewers tend to ask academic and tricky questions which you barely touch on daily basis.
This post will help you cover frequently asked topics by listing as a learning path with short introduction and optional links to further reading, reread before interviews to see the big picture and fill the gaps as you go.
This post is dedicated to JavaScript language itself; don’t be confused with APIs of host environments, features of JavaScript frameworks, features of static type checkers, and also be careful with early-stage proposal features.
JavaScript language itself is quite small and easy to learn; but the ecosystem around it is huge, overlapped, borrowed, opinionated, incomplete, and not centrally well documented. This is okay to me as an experienced engineer, working with JavaScript these days is fun and long lasting exciting. However it does cause some troubles with beginners and interviewing candidates when they might get lost and overwhelmed.
Let’s cover the evolution of JavaScript over the years, how it is executed in different host environments, how to structure and reuse codebase, and some advanced features to make it a complete powerful general-purpose programming language.
JavaScript was created as merely browser scripting language in the old days with very few features and extremely error-prone, and that still remains as the main impression to non-JavaScript developers until these days.
Don’t judge JavaScript by its bad parts, learn the good stuff and stick with that! It is the only language that I’m aware of that people feel they don’t need to learn before they start using it.
Since ECMAScript 2015 (ES6) Specification, JavaScript has been considered as a general-purpose multi-paradigm programming language. This language has a very ambitious future when community tends to use it in all kinds of platform like browser, desktop, mobile, embedded and command line. Check this repo es6features to have an overview of all ES6 features.
JavaScript before ES6 is very sloppy, but we can’t get rid of old features because the golden rule of don't break the web
. Community has tried to enhance JavaScript with multiple stuff like:
After big update ES6, JavaScript has gone through multiple small updates each year. Don’t forget to follow latest proposals which you can adopt early via babel.
The execution of a JavaScript program involves many floating parts like JavaScript engines (heap, stack) and host environments (APIs, callback queue, event loop). Watch this excellent video by Philip Roberts:
V8 is the most famous JavaScript engine which is used both in Chrome browser and NodeJS, it compiles JavaScript directly to native machine code using just-in-time compilation before executing it, the compiled code is additionally optimized (and re-optimized) dynamically at runtime.
JavaScript programs started off pretty small — most of its usage in the early days was to do isolated scripting tasks, providing a bit of interactivity to your web pages where needed, so large scripts were generally not needed.
JavaScript has had modules for a long time. However, they were implemented via libraries, not built into the language. ES6 is the first time that JavaScript has built-in modules.
CJS (CommonJS, originally called ServerJS) is an ambitious project started by Kevin Dangoor back in 2009 in an attempt to bring JavaScript to the outside of web browsers. The ultimate goal is to define a JavaScript Standard Library like other general-purpose programming languages and compatible in multiple host environments.
AMD (Asynchronous Module Definition) is a module format that allows module and its dependencies can be asynchronously loaded. This is particularly well suited for the browser environment where synchronous loading of modules incurs performance, usability, debugging, and cross-domain access problems.
UMD (Universal Module Definition) is a universal module format which is ugly, but is both AMD and CommonJS compatible, as well as supporting the old-style global
variable definition.
ESM (ES Modules, ECMAScript Modules) is the official standard format to package JavaScript code for reuse, this standardization process completed with ES6 and browsers started implementing this standard trying to keep everything well aligned.
A programming paradigm is a style, or “way,” of programming, they are not meant to be mutually exclusive. A single program can feature multiple paradigms. Very few languages implement a paradigm 100% — when they do, they are pure. It is incredibly rare to have a pure OOP
language or a pure functional
language.
JavaScript programs tend to make heavy use of passing functions around so they are called functional languages despite having variables and many imperative
constructs. You should invest heavily on this topic before any interviews, I can’t emphasize enough how important it is to cover following supported programming paradigms in JavaScript:
Functional Programming — a natural fit for JavaScript because it offers first-class functions, closures, and simple lambda syntax.
Prototype-Based Object-Oriented Programming — when it has classes; when it comes to inheritance, JavaScript supports it in a process of reusing existing objects via delegation that serve as prototypes, also known as prototypal inheritance.
Metaprogramming — with Proxy
and Reflect
objects allowing you to intercept and define custom behavior for fundamental language operations (e.g. property lookup, assignment, enumeration, function invocation, etc).
Event-Driven Programming — via the support of host environments. JavaScript language itself doesn’t support I/O but relied on host environments to coordinate events, user interaction, scripts, rendering, networking, and so forth, host environments must use event loop.
Each paradigm has their own benefits and drawbacks, mix them nicely to build products which are performant, reusable and maintainable.
There is no doubt that function is the heart of JavaScript since its inception, functions are treated as first-class citizens, you can pass functions around like any other data types. This special position makes possible for functional programming in JavaScript.
Functions in JavaScript are more complicated than in other programming languages when they carry too much capabilities, shorthands, and patterns.
It’s a must to fully understand JavaScript functions and surrounding concepts like functional programming
, first-class functions
, arrow function
, scopes
, lexical environment
, closures
, pure functions
, higher-order functions
, currying
.
Object-oriented programming is very popular among developers and software companies, that’s why classes were added to JavaScript to make life easier for beginners and who coming from other object-oriented programming languages.
JavaScript classes have their quirks due to the complexity of having to retain backward compatibility. JavaScript class inheritance is mocked, but underneath (and hidden), it’s still using prototypal inheritance.
Classes don’t fundamentally change how JavaScript works; it’s not introducing a new thing. Classes are simply syntactic sugar on top of the custom types you’ve been working with for a while. This solves a problem that JavaScript has had for a long time, which is the verbosity and confusion of defining your own types.
Classes give us a more concise way of creating object blueprints, and constructor functions describe more accurately what is happening under the hood. Understanding prototypical inheritance is paramount to being an effective JavaScript developer.
Iterators are an implementation of Iterable objects such as maps, arrays and strings which enables us to iterate over them using next(). They have a wide variety of use cases across Generators, Observables and Spread operators.
Generators are functions whose executions are not continuous, they can stop midway and then continue from where they stopped, written using the function*
syntax, appear to be functions but behave like iterators.
Async generators are special because you can use both await
and yield
, different from async functions and generators in that they don’t return a promise or an iterator but rather an async iterator. You can think of an async iterator as an iterator whose next() function always returns a promise.
Any general purpose programming languages must provide a way of writing asynchronous code to handle heavy tasks — I/O operations, calling network requests, writing to files, etc — and JavaScript is obviously one of them.
Callback in JavaScript is a function that is passes as argument to other function that is expected to execute (call back) the argument at a given time; synchronous callbacks are invoked before a function returns, asynchronous callbacks may be invoked after a function returns.
A promise is an object that may produce a single value some time in the future, either a resolved value, or a reason that it’s not resolved, may be in one of 3 possible states — fulfilled, rejected, or pending.
Async functions enable us to write promise based code as if it were synchronous, but without blocking the execution thread. It operates asynchronously via the event-loop. An async function can contain an await expression that pauses the execution of the async function and waits for the passed Promise’s resolution, and then resumes the async function’s execution and evaluates as the resolved value.
Scope is the accessibility of variables, functions, and objects in some particular part of your code during runtime.
Lexical scoping defines how variable names are resolved in nested functions: inner functions contain the scope of parent functions even if the parent function has returned.
Hoisting is a JavaScript mechanism where variables and function declarations are moved to the top of their scope before code execution.
Currying is a process in functional programming in which we can transform a function with multiple arguments into a sequence of nesting functions. It returns a new function that expects the next argument inline.
Regular expression is an object that describes a pattern of characters, RegExp
class represents regular expressions, and both String and RegExp define methods that use regular expressions to perform powerful pattern-matching and search-and-replace functions on text.
Mixin is a class containing methods that can be used by other classes without a need to inherit from it. A mixin provides methods that implement a certain behavior, but we do not use it alone, we use it to add the behavior to other classes.
JavaScript is no longer confined to the browser, it runs everywhere and on anything, from servers to IoT devices; learning it properly will increase your chances of finding a good job or building a successful startup.
Inexperienced technical interviewers are unpredictable and prefer to challenge you than wish you succeed. More experienced ones are wiser, they seem to know your levels already and believe that you can reach to where they are by learning the right things.
Failing to list all possible cases is fine, but having no clue of something is definitely a red flag
Reread this post multiple times to familiarize all keywords and concepts, keep digging deep on unfamiliar ones by searching Google or reading following excellent resources: