Development Tips

Modern JavaScript for Business Websites: What ES6+ Means in 2026

By Ken Key Sep 25, 2024 6 min read Updated Oct 16, 2026

Modern JavaScript for Business Websites: What ES6+ Means in 2026
The short answer

ES6+ means writing JavaScript with modern syntax like let, const, arrow functions, and async/await, then letting a build step handle older browsers. In 2026 every browser supports these natively, so the real win is maintainable code that's faster to update and cheaper to own.

Part of the complete web development guide.

On this page

ES6 (officially ECMAScript 2015) shipped over a decade ago, and it’s now the baseline for every browser in use. If you’re still running a script tag full of var and jQuery callbacks, your site works, but it’s fighting you. Here’s what actually matters in 2026 and why it’s worth cleaning up.

I’ve been building and maintaining sites for businesses around Commack and the rest of Long Island for years, and the pattern is always the same: the code from 2014 still runs, but every small change takes twice as long as it should. Modern JavaScript fixes that, and it’s less about fashion than about maintainability.

ES6 was the last big language change. Everything since has been incremental.

People talk about “ES6” like it’s a version you adopt. It isn’t. It’s the line where JavaScript got the features other languages had for twenty years, and every yearly release since (ES2017, ES2018, up through ES2025) has been smaller. So when someone says “I write ES6,” what they usually mean is “I write modern JavaScript.” Those are three things worth separating:

  • Syntax features you write in your source: arrow functions, let/const, template literals, destructuring, classes, spread.
  • Runtime features the browser provides: Promises, fetch, modules, async/await, Map/Set.
  • Tooling that decides what actually ships to visitors: bundlers, transpilers, minifiers.

Confusing these is how people end up with a 400KB bundle to display a dropdown menu. You don’t need a build step for everything.

The features that actually change how you write code

let and const, and why var is a bug factory

var is function-scoped and hoisted, which means it leaks out of blocks and lets you redeclare the same name without complaint. let and const are block-scoped. In practice, that removes an entire category of “why is this variable the wrong value” bugs.

// Old: i leaks, and every handler logs 3
for (var i = 0; i < 3; i++) {
 setTimeout(() => console.log(i), 0);
}

// Modern: each iteration gets its own binding
for (let i = 0; i < 3; i++) {
 setTimeout(() => console.log(i), 0);
}
// logs 0, 1, 2 instead of 3, 3, 3

Default to const. Reach for let when you genuinely reassign. You should basically never type var again in new code.

Arrow functions and the this problem

Arrow functions don’t have their own this. They inherit it from the surrounding scope. That kills the var self = this; workaround people used to write constantly.

class ContactForm {
 constructor(form) {
 this.form = form;
 this.form.addEventListener('submit', (event) => {
 event.preventDefault();
 this.submit(); // `this` is the instance, no binding needed
 });
 }

 submit() {
 // ...
 }
}

One caveat worth knowing: because arrows don’t bind their own this, they’re a bad fit for object methods you want to reuse on other objects, and they can’t be used as constructors. That’s a feature, not a limitation, but it trips people up.

Template literals over string concatenation

const name = 'Dana';
const count = 3;

// Old
const msg = 'Hi ' + name + ', you have ' + count + ' new messages.';

// Modern
const msg = `Hi ${name}, you have ${count} new messages.`;

Multi-line strings work too, which matters more than it sounds when you’re building HTML fragments or SQL.

Destructuring and spread

These two cut a surprising amount of noise, especially when you’re dealing with API responses.

// Destructuring with a default and a rename
const { id, title: headline, tags = [] } = post;

// Spread to copy without mutating
const updated = { ...post, title: 'New headline' };
const combined = [...listA, ...listB];

The important part is that spread copies. React and most modern UI code assumes you never mutate state directly, and spread is how you avoid it.

Async code is where old scripts really fall apart

The biggest practical difference between 2014 JavaScript and 2026 JavaScript isn’t syntax. It’s how you handle anything that takes time: network calls, file reads, animations.

Promises and async/await

async function loadUser(id) {
 try {
 const res = await fetch(`/api/users/${id}`);
 if (!res.ok) throw new Error(`Request failed: ${res.status}`);
 return await res.json();
 } catch (err) {
 console.error('Could not load user', err);
 throw err;
 }
}

That replaces a pyramid of nested callbacks with something you read top to bottom. Two things people get wrong:

  • await inside a loop runs sequentially. If the requests are independent, kick them off together with Promise.all.
  • fetch does not reject on a 404 or 500. It only rejects on network failure. You have to check res.ok yourself. This one causes real bugs in production.
// Sequential: slow, one at a time
for (const id of ids) {
 results.push(await loadUser(id));
}

// Concurrent: all at once
const results = await Promise.all(ids.map(loadUser));

What about top-level await and modern module loading?

ES modules are now the default. You write import and export instead of juggling globals and script order, and browsers load them natively with type="module":

<script type="module" src="/js/app.js"></script>
// app.js
import { formatPrice } from './format.js';

const total = formatPrice(1999);
document.querySelector('#total').textContent = total;

Modules are deferred by default, scoped to themselves, and loaded once no matter how many files import them. If you’ve been maintaining a site with fifteen script tags in a specific order that nobody dares reorder, this is the fix.

Do you still need a build step in 2026?

Less than you used to. Native ES modules, fetch, optional chaining, and ?? are all baseline in current browsers. For a marketing site or a small app, plain modules plus a minifier can be entirely sufficient. No framework required.

Where tooling still earns its keep:

  • TypeScript if you have more than a couple of developers or a codebase that changes often. Types catch the mistakes you’d otherwise catch in production.
  • Bundling when you have hundreds of modules and want to cut HTTP requests, though HTTP/2 and HTTP/3 have made this far less urgent than it was in 2016.
  • Transpiling only for the browsers you actually need to support. Check your analytics before you decide. Shipping ES5 to everyone in 2026 is usually wasted bytes.

If you’re weighing a rebuild against a cleanup, that’s a judgment call about your specific site, not a rule. I do custom web development for local businesses and the honest answer is usually “clean up the parts that hurt, leave the rest alone.”

Common mistakes I see in inherited code

  • Mixing var and let in the same file. Pick one and be consistent.
  • Using == instead of ===. Loose equality does type coercion and will surprise you. [] == false is true.
  • Mutating arrays and objects that other code holds a reference to. Spread instead.
  • Forgetting that await in a loop is sequential, then wondering why the page is slow.
  • Assuming fetch throws on HTTP errors. It doesn’t.
  • Loading everything as one giant bundle when half the code only runs on one page.

Should you rewrite your old scripts?

No, not wholesale. Rewrites are where budgets go to die. The better approach is to modernize as you touch things: when you fix a bug in a file, convert that file. Set 'use strict' expectations, switch to const/let, replace callback chains with async/await as you go. Over a year, a messy codebase becomes a readable one without a single risky big-bang deploy.

If it’s working and nobody’s touching it, leave it alone. Boring and stable beats modern and broken.

FAQ

Is ES6 still relevant in 2026?

Yes, but as a floor rather than a ceiling. Everything in ES6 is supported in every current browser, and the yearly releases since have added smaller features on top. The real question isn’t whether to use ES6, it’s whether you’re still writing pre-ES6 code for no reason.

Do I need a bundler to use modern JavaScript?

Usually not. Native ES modules work in all current browsers, so a small site can ship type="module" scripts directly. Bundlers still help with very large codebases or heavy dependency trees, but they’re not the requirement they were a decade ago.

How do I know if my site’s JavaScript is outdated?

Open the source and look for var, nested callbacks, jQuery-only DOM manipulation, and script tags that have to load in a specific order. Any of those means the code will be harder to change than it needs to be. That’s the real cost, not performance.

Have a project like this?

I do custom web development for Long Island businesses. If you need this done right, let’s talk.