Programming
October 19, 2023
10 min read
JavaScript is one of the core technologies of the web, enabling interactive web pages and powerful web applications. In this section, we'll cover a brief history of JavaScript, an overview of its key features, modern ES6+ syntax, how it interacts with browsers, and some of the popular frameworks and tools commonly used alongside it.
JavaScript was created in 1995 by Brendan Eich at Netscape as a way to add dynamic interactivity and logic to web pages. Originally called LiveScript, it was later renamed to JavaScript as a marketing decision to capitalize on the popularity of Java at the time.
Despite the name, JavaScript is unrelated to Java. JavaScript quickly became essential for web developers wanting to create interactive buttons, form validations, animations, and more. It enabled web pages to respond to user input without requiring page refreshes.
Over the years, new ECMAScript standards have added major improvements to the language. ES6, released in 2015, introduced important features like classes, arrow functions, promises, and destructuring that streamlined development. The latest ES2022 standard brings pattern matching and other capabilities.
Today, JavaScript remains the most widely used programming language in web development. It powers complex web applications from companies like Google, Facebook, Twitter, and more.
JavaScript provides core programming language fundamentals like:
With these building blocks, JavaScript enables adding logic and dynamism to web pages in the browser.
While JavaScript provides the core fundamentals, modern standards like ES6+ have added many improvements:
These features streamline development and prevent common bugs.
JavaScript uses a single-threaded, non-blocking execution model. Code executes line by line during the call stack, while asynchronous actions get sent to a callback queue handled by the event loop.
This event loop coordination enables non-blocking asynchronous behavior critical for dynamic web apps. Understanding this model is key for effective architecture.
While JavaScript rose to prominence as a browser scripting language, today it powers software engineering far beyond the browser. The runtime environment Node.js enabled running JavaScript on servers. This allowed building full stack JavaScript apps and opened the doors to using it for back end development.
JavaScript now provides full application platform capabilities spanning web, mobile, desktop, IoT devices, databases, machine learning, and more. Its versatility and ubiquity make it a highly valuable skill.
Variables and data types are building blocks in any language. Let's explore how they work in JavaScript.
The let
and const
keywords allow declaring block scoped variables in JavaScript:
// Declare variable with let
let myVariable = 'Hello';
// Declare constant with const
const myConstant = 42;
let
declares a variable that can be reassigned laterconst
declares a constant that cannot be reassignedPrefer using const
by default for better code. let
and const
fix issues with global scope in var
.
JavaScript provides data types for:
true
and false
JavaScript dynamically allows assigning these data types to variables at runtime.
Operators perform actions on values and variables:
+
), subtract (-
), multiply (*
), divide (/
)=
, compound assignment like +=
<
, >
, <=
, >=
, ==
, ===
&&
, ||
, !
A key aspect of JavaScript is its flexible dynamic typing system. Variables can hold values of any data type and seamlessly change types on the fly.
JavaScript is also weakly typed regarding conversions and comparisons, meaning it coerces types during operations. This provides flexibility but can also lead to subtle bugs.
In JavaScript, ==
and ===
both check equality between values or variables. The key difference is that:
==
coerces type conversion during comparison===
checks equality without type coercionThe ==
operator with type coercion can have unintended consequences leading to bugs, so ===
is preferred in most cases for safety and explicitness.
Functions, scope, and conditionals are core programming concepts that JavaScript provides familiar semantics for.
Functions are blocks of reusable code that can accept parameters, execute logic, and return values. In JavaScript they can be declared with function
or =>
arrow syntax.
// Regular function declaration
function add(x, y) {
return x + y;
}
// Arrow function expression
const add = (x, y) => {
return x + y;
}
JavaScript functions are first-class objects, meaning they can be assigned to variables, passed to other functions, and returned from functions. This enables powerful functional programming patterns.
Variables declared within a JavaScript function are locally scoped to that function and are not accessible from the outside scope. Functions can access variables in the outer scope through closures.
Immediately invoked function expressions (IIFEs) are often used to create locally scoped blocks without polluting the global namespace.
Conditionals execute different code paths based on Boolean logic:
if
and else
statements check specific conditionsswitch
statements match casesConditionals rely on the concept of truthy and falsy values in JavaScript, where values have an inherent Boolean nature when assessed in conditional contexts.
Objects and arrays enable working with structured data, while loops allow iterating over them.
Objects store data in key-value pairs and can be created either with object literals {}
or the Object()
constructor.
// Object literal
const person = {
name: 'John',
age: 30
};
// Accessing properties
person.name; // 'John'
person.age; // 30
// Adding properties
person.job = 'Teacher';
Objects support dynamically adding, removing, and accessing properties. Useful methods like Object.assign()
and the spread operator make copies of objects.
Destructuring is a convenient way to declare variables mapped to object properties.
Arrays represent ordered lists of data and create sequence-based data structures. Standard array methods like push
, pop
, unshift
, shift
make adding and removing elements easy.
const fruits = ['Apple', 'Banana'];
// Array operations:
fruits.push('Orange'); // ['Apple', 'Banana', 'Orange']
fruits.pop(); // 'Orange'
fruits.unshift('Strawberry'); // ['Strawberry', 'Apple', 'Banana']
// Iterating an array:
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
Arrays have a length
property and are accessed via zero-based numeric indexes. Loops like for
are well-suited for iterating over arrays.
Common looping keywords like for
, while
, do-while
enable iterating through arrays, objects, and other data structures.
for..in
loops through the keys of an object, while for..of
loops through the values of any iterable like arrays.
Being able to iterate collections and strings is vital for practical JavaScript code.
While JavaScript takes a unique approach to object-oriented code, familiar OOP patterns can be implemented via constructor functions and prototypes. ES6 added syntactic sugar making inheritance implementation more ergonomic.
Instead of classes, JavaScript uses a prototype-based inheritance model. Objects inherit directly from other objects via the internal [[Prototype]]
property. This enables dynamic inherited behavior while still preserving object flexibility.
Before ES6, JavaScript implemented OOP style patterns through constructor functions. Constructor functions create object instances. Methods and properties can be attached to the constructor's prototype
object to be shared across instances.
ES6 introduced class
syntax on top of the prototypal inheritance model as mostly syntactic sugar. The class
keyword and extends
make inheritance clearer. Under the hood, they still use constructor functions and prototypes.
class Vehicle {
constructor() {
this.speed = 0;
}
accelerate() {
this.speed++;
}
}
class Car extends Vehicle {
// Inherits accelerate()
constructor() {
super();
this.wheels = 4;
}
}
The static
keyword defines methods called directly on the class constructor rather than instances. Getters/setters control access to properties. Private properties can be implemented via closures or WeakMaps.
JavaScript uses an asynchronous, event-driven programming model critical for handling I/O operations and delivering reactive user experiences.
Callbacks are functions passed as arguments to other functions that start async actions. The callback fires upon completion so code executes non-linearly. Callback-heavy code risks pyramid "callback hell".
Promises represent the result of future operations and improve callback-driven async code. They can resolve with a value or reject with an error. Promises enable chaining with .then()
/.catch()
instead of nested callbacks.
function delay(time) {
return new Promise((resolve) => {
setTimeout(resolve, time);
});
}
delay(500)
.then(() => {
console.log('500 ms passed');
return delay(200);
})
.then(() => {
console.log('200 ms passed');
});
The async/await
syntax allows writing Promise-based async code as if it were synchronous, pausing execution until Promises resolve. Error handling is also cleaner using try/catch
.
Async/await provides sequential async workflows. The async
keyword must be present on enclosing functions.
Beyond language fundamentals, JavaScript underpins complex applications and delivers robust user experiences at scale across industries.
Many frameworks and libraries build on vanilla JavaScript:
Node.js enabled running JavaScript on servers outside browsers by implementing the Chrome V8 engine in a standalone runtime. This allowed building server-side applications with JavaScript.
Node's simple APIs, cross-platform nature, and expansive ecosystem via NPM fueled widespread back end adoption. Node.js facilitated full stack JavaScript.
Beyond front end and back end web development, JavaScript sees expanded use cases like:
The flexibility and maturity of JavaScript make it a versatile language well-suited for many domains.
We've explored JavaScript from its historical roots to modern ES6+ features, core language fundamentals, web and server-side programming models, asynchronous patterns, and real-world use cases.
JavaScript remains an essential language for any web developer as the underpinning of interactive web experiences. Its popularity and support across environments make JavaScript a valuable skill for any engineer aiming to build robust full stack or cross-platform applications.
For those looking to dive deeper, the Learn JavaScript site offers interactive lessons, challenges, and projects tailored for all levels to master JavaScript at your own pace.