MacMusic  |  PcMusic  |  440 Software  |  440 Forums  |  440TV  |  Zicos
javascript
Search

8 ways to do more with modern JavaScript

Wednesday May 7, 2025. 11:00 AM , from InfoWorld
JavaScript is an incredibly durable, versatile, and capable language, and often provides everything you need right out of the box. The foundation for success is knowing the full expanse of what JavaScript offers and how to leverage it in your programs. Here are eight key concepts for developers who want to get the most out of the universe of tools and libraries available in JavaScript today.

Use variable declarations

Although variables are as old as programming itself, they’re still a key concept in modern JavaScript. To start, consider that we prefer const over let in JavaScript programming. Why is that?

A const declares a constant, which is a variable that does not change. We use const any time we can because its immutability makes it less complex. You don’t have to think about how an immutable variable behaves or how it might change throughout the life of the program. const lets you store a value so you can use it wherever you want, without worrying about what would happen if that value changed.

Immutability is a quietly profound concept that echoes throughout software design, especially in functional and reactive programming, where it is leveraged to simplify the overall structure of larger systems.

Something else that is important to know about const is how it works on objects and collections. In these cases, const works to prevent changing the reference to the variable, but it does not prevent alterations to the variable’s internal state. This reveals something important about the internal structure of JavaScript. (Under the hood, object and collection variables are pointers, which means they hold a place in memory. Choosing to use const means we can’t change the place.)

Of course, there are times when we need a variable that truly is a variable, and for that, we use let. JavaScript also has a var keyword. Knowing the difference between let and var can help you understand variable scoping, which helps with more advanced ideas like scopes and closures, which I’ll discuss shortly.

The let declaration restricts the variable to the block where it is declared, whereas var “hoists” its variable to the containing scope. var is more visible and also more prone to error. It’s a good idea to refactor using let whenever you find a var in your code.

Understand collections and functional operators

Functional operators are some of the coolest and most powerful features of modern JavaScript. Operators like map, flatMap, reduce, and forEach let you perform repetitions on collections with a clean, self-documenting syntax. Especially for simpler operations, functional programming constructs like these can make your code read very directly, giving you the meaning you need without a lot of verbiage related to iteration.

When you are writing a program, you are usually trying to handle some kind of business function—say, taking a response from an API and doing something to it based on user input. Within that task, you need a loop, but the loop is just a necessary bit of logic that supports the overall intention. It shouldn’t take up too much space in the program. Functional operators let you describe the loop with minimal obscuring of the overarching meaning.

Here’s an example:

const albums = [
{ artist: 'Keith Jarrett', album: 'The Köln Concert', genre: 'Jazz' },
{ artist: 'J.S. Bach', album: 'Brandenburg Concertos', genre: 'Classical' },
{ artist: 'The Beatles', album: 'Abbey Road', genre: 'Rock' },
{ artist: 'Beastie Boys', album: 'Ill Communication', genre: 'Hip Hop'}];

genreInput = 'rock';

console.log(
albums.filter(album => album.genre.toLowerCase() === genreInput.toLowerCase())
)

The overall intention of the above code is to filter the list of albums based on genre. The built-in filter method on the albums array returns a new collection with the passed-in function applied. (This style of returning rather than manipulating the original array is another example of immutability in action.) 

The looping logic is reduced to its simple essence in service of the surrounding meaning. It’s worth noting that traditional loops still have a huge role to play, especially in very complex loops with multiple iterators, or in very large loop bodies where the curly-braced code blocks can simplify following things, particularly with nested loops.

Take advantage of promises and async/await

Asynchronous programming is inherently tricky because it by definition involves multiple actions occurring at once. This means we have to think about the interleaving of events. Fortunately, JavaScript has strong abstractions around these concepts. Promises are the first line of defense in managing async complexity and the async/await keywords give you another layer on top of promises. You can use async/await to write asynchronous operations in a synchronous-looking syntax.

As a software developer, you often consume promises or async functions in libraries. The ubiquitous fetch function built into the browser (and also server-side platforms like Node) is a great example:

async function getStarWarsPerson(personId) {
const response = await fetch(`https://swapi.dev/api/people/${personId}/`);
if (response.ok) {
//...
}

The function we define has async on it, while the function we consume (fetch) is modified with await. It looks like a normal line of synchronous code but it allows the fetch to happen in its own time, followed by whatever comes next. This sequence frees the event loop to do other things while the fetch proceeds. (I left out error handling in this example, but I address it a little further down.)

Promises are not too difficult to understand, but they do put you more into the semantics of actual asynchronous operations. This makes them more involved, but also quite powerful. The idea is that a Promise object represents an asynchronous operation and its resolve and reject methods represent the outcome. Client code then handles the results using the callback methods then() and catch().

One thing to keep in mind is that JavaScript is not truly concurrent. It uses asynchronous constructs to support parallelism but there is only one event loop, representing a single operating system thread.

Know these five syntax shortcuts

For evidence of JavaScript’s commitment to improving developer experience, look no further than its powerful shortcuts. These are slick operators that make mere keystrokes of some of the most common and clunky corners of JavaScript programming.

Spread

The spread operator (or ellipses operator) lets you reference the individual elements of an array or object:

const originalArray = [1, 2, 3];
const copiedArray = [...originalArray];
copiedArray.push('foo'); // [1,2,3,’foo’]

Spread also works for objects

const person = { name: 'Alice', age: 30 };
const address = { city: 'New York', country: 'USA' };
const fullInfo = {...person,...address };

Destruct

Destructing gives you a shorthand to “expand” the elements of an array or object into its parts:

const colors = ['red', 'green', 'blue'];
const [firstColor] = colors;
firstColor === “red”;

const person = { name: 'Alice', age: 30, city: 'London' };
const { city } = person;
city === “London”;

This sweet syntax is often seen when importing modules, among other things:

const express = require('express');
const { json, urlencoded } = require('express');

Destructing also supports named parameters and defaults.

Optional chaining

Optional chaining takes the old practice of manual null checks and turns it into a single, breezy operator:

const street = user?.profile?.address?.street;

If any of the roots or branches in that dot access chain are null, the whole thing resolves to null (instead of throwing a null pointer exception). This should give you a welcome sigh of relief.

Logical assignment

Logical assignment comes in and, or, and strict nullish variants. Here’s the latter:

let myString = null;
myString??= “Foo”;
myString??= “Bar”;
myString === “Foo”;

Note that myString only changes if it’s actually null (or undefined).

Nullish coalescence

Nullish coalescence lets you easily choose between a variable that might be null and a default:

let productName = null;
let displayName = productName?? 'Unknown Product';
productName === “Unknown Product”;

These niceties are a distinctive characteristic of modern JavaScript. Using them judiciously makes your code more elegant and readable.

Do not fear scopes and closures

When it comes to the nuts and bolts of using JavaScript as a language, scopes and closures are essential concepts. The idea of scope is central to all languages. It refers simply to a variable’s visibility horizon: once you declare a variable, where can it be seen and used?

A closure is the way a variable’s scope acts in special circumstances. When a new function scope is declared, the variables in the surrounding context are made available to it. This is a simple idea—don’t let the fancy name fool you. The name just means the surrounding scope “closes around” the inner scope.

Closures have powerful implications. You can use them to define variables that matter to your larger context, then define chunks of functional blocks that operate on them (thereby strongly containing or encapsulating your logic). Here’s that concept in pseudocode:

outer context
variable x
function context
do stuff with x
x now reflects changes

The same idea in JS:

function outerFunction() {
let x = 10;

function innerFunction() {
x = 20;
}

innerFunction();
console.log(x); // Outputs 20
}

outerFunction();

In the above example, innerFunction() is a closure. It accesses the variable from its parent scope (also known as the lexical scope, signifying the closure has access to the variables in scope where it is declared, rather than where it is called).

As I mentioned earlier, one of the tenets of functional programming is immutability. This is the idea that for clean designs, we avoid changing variables. Modifying x in our example goes against this guideline. Accessing the variable, though, is an essential ability. The key is to understand how it works.

This kind of closure use is even more important with functional collection operators like map and reduce. These give you a very clean syntax for doing things, and they also have access to the lexical scope where they are declared.

Fail gracefully (error handling)

Did you know that errors in computing were once called bugs because actual moths were flying into the circuits? Now we have bugs because our AI assistants confidently generate code that breaks in ways we can’t unpredict (more about that below).

As programmers, we’ll never outgrow strong error-handling practices. Fortunately, modern JavaScript enhances error handling so that it’s fairly sophisticated. It comes in two basic varieties: normal, synchronous code errors, and asynchronous event errors. Error objects sport error messages and cause objects as well as stack traces, which are dumps of the call stack when the error happened.

The main mechanism for normal errors in the good old try-catch-finally block and their origin, the throw keyword. Asynchronous errors are a bit more slippery. The syntax, using catch callbacks and reject calls on promises, along with catch blocks for async functions, is not too complex. But you need to keep an eye on those async calls and make sure you’re handling everything.

User experience is greatly impacted by careful error handling: Fail gracefully, track errors, don’t swallow errors … that last one is a very embarrassing mistake (ask me how I know).

Use the programming style that works

This one is just applied common sense. In essence, the wise JavaScript developer is ecumenical when it comes to programming paradigms. JavaScript offers object-oriented programming, functional programming, imperative programming, and reactive programming styles. Why wouldn’t you make the most of that opportunity? You can build your program around one style or blend them depending on the use case.

Modern JavaScript has strong class support as well as prototype inheritance. This is typical of JavaScript: there’s more than one way to do it, and no particular right way. Classes are so well known in the object-oriented world we mostly use them these days, but prototypes are still useful and important to know about.

JavaScript has also made functional programming popular. It has been such an effective ambassador of the approach that other languages—even strong object-oriented ones like Java—have adopted aspects of functional programming into their core. Especially when dealing with collections, functional operators are just what you need sometimes.

JavaScript is also a champion reactive language, with popular reactive tools like RxJS and Signals. Note that reactive programming is a broad and interesting topic, and not to be confused with reactive frameworks like Angular and React. They are not the same thing.

Also, don’t forget that JavaScript was originally a scripting language—it’s right there in the name. Sometimes, a good old imperative script is exactly the right level of detail for the job at hand. Don’t hesitate to go that way if it’s what you need, especially in a one-off systems utility.

There are lots of ways to use JavaScript. Don’t cheat yourself by sticking with just one.

A word about AI assistance

First of all, let’s acknowledge that AI programming is incredibly useful. We’ve only had AI programming assistants for a short time, yet already it would be almost unthinkable to build software without using some kind of AI coding assistance.

I say almost because this is also true of modern IDEs. You’d think that no one would want to develop without using something like VS Code, IntelliJ, or Eclipse. But, the fact is, I’ve seen developers who use the Posix command line together with Vim or Emacs in a way that makes a visual IDE with a mouse look clunky. You have to see the speed and efficiency of arcane hotkeys, muscle memory, and system knowledge in action to believe it.

As developers, we are going to make excellent use of AI coding in much the same way we make good use of IDEs. Some developers might code more effectively without it, but that’s because they’ve mastered the essentials. They can perceive maximum-value changes and make them, even in large and complex systems.

No matter what tools we use, the better we know our fundamentals, the better off we and our programs will be. The fundamentals translate across languages, frameworks, platforms, and operating systems, and underpin coding in both small and large implementations. There is nothing more gratifying than seeing the benefit of all that learning and groundwork you’ve done while talking to stakeholders about a critical project.

AI can’t do that for you, but you can use AI tools to empower your commitment to programming.
https://www.infoworld.com/article/3977605/8-ways-to-do-more-with-modern-javascript.html

Related News

News copyright owned by their original publishers | Copyright © 2004 - 2025 Zicos / 440Network
Current Date
May, Thu 8 - 21:06 CEST