Tari Ibaba is a software developer with years of experience building websites and apps. He has written extensively on a wide range of programming topics and has created dozens of apps and open-source libraries.
Can you break out of a “forEach” loop in JavaScript?
It’s an amazing question to challenge just how well you really know JavaScript.
Because we’re not talking for loops — or this would have been ridiculously easy: you just break:
But you wouldn’t dare do this with forEach, or disaster happens:
What about return… mhmm.
What do you think is going to happen here:
return should easily end the loop at 5 and take us to the outer log right?
Wrong:
Remember: forEach takes a callback and calls it FOR EACH item in the array.
JavaScriptCopied!
// Something like this:
Array.prototype.forEach = function (callback, thisCtx) {
const length = this.length;
let i = 0;
while (i < length) {
// 👇 callback run once and only once
callback.call(thisCtx, this[i], i, this);
i++;
}
};
So return only ends the current callback call and iteration; doing absolutely nothing to stop the overall loop.
It’s like here; trying to end func2() from func1() — obviously not going to work:
5 terrible ways to stop a forEach loop
1. Throw an exception
You can stop any forEach loop by throwing an exception:
JavaScriptCopied!
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
try {
nums.forEach((num) => {
if (num === 5) {
throw new Error('just to stop a loop?');
}
console.log(num);
});
} catch {
console.log('finally stopped!');
}
Of course we’re just having fun here — this would be horrible to see in real-world code. We only create exceptions for problems, not planned code like this.
What if we don’t want to completely override it, but instead extend it in an intuitive way?
We can’t use instanceof inside the symbol because that’ll quickly lead to an infinite recursion:
Instead we compare the special constructor property of the object to our own:
JavaScriptCopied!
class Fruit {
constructor(name) {
this.name = name;
}
[Symbol.hasInstance](obj) {
const fruits = ['🍍', '🍌', '🍉', '🍇'];
// this == this.constructor in a static method
return obj.constructor === this || fruits.includes(obj);
}
}
const fruit = new Fruit('apple');
If you’re just hearing of .constructor, this should explain everything:
From looping to splitting to searching, well-known symbols let us redefine our core functionalities to behave in unique and delightful ways, pushing the boundaries of what’s possibly in JavaScript.
Lottie takes the magic from Adobe After Effects and brings it straight to your mobile and web apps.
Imagine the experience needed to create this 👇 Then imagine recreating it with raw CSS.
So no more hand-coding – Lottie uses a special plugin to turn those After Effects animations into a lightweight JSON format that works flawlessly on any device.
I use this often when having nasty bugs with JSON web token from Firebase Auth or some stuff.
You just paste your token on the left and you instantly see the decoded value on the right.
And using this got me confused at first; I thought JWT was like an encryption where only the receiver could know what was there with the secret?
But no; it turned out JWT is for verifying the source of the message, not hiding information. Like in crypto wallets and transactions private and public keys.
Coding is the art of bringing thoughts into digital and physical reality.
I love this definition; so many gems to unpack from 1 concise statement.
With coding we wield the power to shape the digital realm according to our imagination and needs.
Picture this: You’re sitting in front of a blank canvas, armed with nothing but your thoughts and a bunch of dev tools.
With a few lines of code, you summon objects into existence, breathe life into algorithms, and orchestrate systems that operate with precision and purpose.
In this digital realm you are the architect, the creator, the god of your own universe. Every line of code is a brushstroke, painting the landscape of your creation.
You design the story of execution, from the inception of an idea to its realization, with the potent aid of lightning-fast computers that transform your commands into tangible results.
Coding is a force amplifier.
Thanks to iteration, recursion, and more, tiny scripts can easily complete unbelievable amounts of work in fractions of a second; work that no one on their own could possibly hope to finish in 10 life times.
Or operating continuously, 24/7, even when everyone is asleep, and throughout all seasons and holidays.
You breathe life into those inert lines of text, imbuing them with functionality and purpose. Bringing forth programs and applications that serve myriad functions; from simplifying mundane tasks to revolutionizing entire industries.
The mere challenge of carefully constructing a complex software system from the growing gives you a strong sense of self-accomplishment, achievement and inner power.
Even going beyond ourselves, coding is a gateway to solving real-world problems that surround us. From streamlining business operations to revolutionizing healthcare, coding empowers us to tackle challenges with efficiency and innovation.
Coding enables us to innovate continually, pushing the boundaries of what is possible and driving progress forward. Whether it’s developing groundbreaking applications, pioneering new technologies, or optimizing existing systems, coding empowers us to make an impact on a global scale.
Consider the countless innovations that have reshaped our world: from social media to e-commerce to the AI tools many of us have gone crazy about; each breakthrough stems from the minds of individuals who dared to dream and had the skills to code their visions into reality.
Apps that never once existed; now brought into existence with the power of thought; now installed in the devices of billions across all the nations of the globe; now influencing lives every single day.
In our information age being able to code is like possessing a superpower—an ability to wield technology as a force for good, to shape the world in ways previously unimaginable. With coding we have the power to improve the quality of life for billions, to democratize access to information and opportunity, and to pave the way for a brighter, more connected future.
Coding is more than just a technical skill—it is a catalyst for change, a tool for empowerment, and a gateway to infinite possibilities. With it we can shape a future that’s not only technologically advanced but also as close to utopia as we can get.
Simply put: Coding a better world into existence for all, enjoying every step along the way.
Typical use case for nested ifs: you want to perform all sorts of checks on some data to make sure it’s valid before finally doing something useful with it.
Don’t do this! 👇
JavaScriptCopied!
function sendMoney(account, amount) {
if (account.balance > amount) {
if (amount > 0) {
if (account.sender === 'user-token') {
account.balance -= amount;
console.log('Transfer completed');
} else {
console.log('Forbidden user');
}
} else {
console.log('Invalid transfer amount');
}
} else {
console.log('Insufficient funds');
}
}
There’s a better way:
JavaScriptCopied!
// ✅
function sendMoney(account, amount) {
if (account.balance < amount) {
console.log('Insufficient funds');
return;
}
if (amount <= 0) {
console.log('Invalid transfer amount');
return;
}
if (account.sender !== 'user-token') {
console.log('Forbidden user');
return;
}
account.balance -= amount;
console.log('Transfer completed');
}
See how much cleaner it is? Instead of nesting ifs, we have multiple if statements that do a check and return immediately if the condition wasn’t met. In this pattern, we can call each of the if statements a guardclause.
If you do a lot of Node.js, you’ve probably seen this flow in Express middleware:
Because the lines must be printed, we print them in the guard clause before returning. And then, we print it in all(!) the following guard clauses. And once again, in the main function body if all the guard clauses were passed.
So what can we do about this? How can we use guard clauses and still stick to the DRY principle?
Well, we split the logic into multiple functions:
JavaScriptCopied!
function func(cond1, cond2) {
checkCond1(cond1, cond2);
console.log('after cond1 check');
}
function checkCond1(cond1, cond2) {
if (!cond1) {
console.log('failed condition 1');
return;
}
checkCond2(cond2);
console.log('after cond2 check');
}
function checkCond2(cond2) {
if (!cond2) {
console.log('failed condition 2');
return;
}
console.log('PASSED!');
console.log('taking success action...');
}
Let’s apply this to the Express middleware we saw earlier:
In a way, we’ve replaced the if/else statements with a chain of responsibility pattern. Of course, this might be an overkill for simple logic like a basic Express request middleware, but the advantage here is that it delegates each additional check to a separate function, separating responsibilities and preventing excess nesting.
Key takeaways
Using nested ifs in code often leads to complex and hard-to-maintain code; Instead, we can use guard clauses to make our code more readable and linear.
We can apply guard clauses to different scenarios and split them into multiple functions to avoid repetition and split responsibilities. By adopting this pattern, we end up writing cleaner and more maintainable code.
JavaScript has come a long way in the past 10 years with brand new feature upgrades in each one.
Still remember when we created classes like this?
JavaScriptCopied!
function Car(make, model) {
this.make = make;
this.model = model;
}
// And had to join strings like this
Car.prototype.drive = function() {
console.log("Vroom! This " + this.make +
" " + this.model + " is driving!");
};
Yeah, a lot has changed!
Let’s take a look at the 5 most significant features that arrived in ES14 (2023); and see the ones you missed.
1. toSorted()
Sweet syntactic sugar.
ES14’s toSorted() method made it easier to sort an array and return a copy without mutation.
They were other features but ES14 was all about easier functional programming and built-in immutability.
With the rise of React we’ve seen declarative JavaScript explode in popularity; it’s only natural that more of them come baked into the language as sweet syntactic sugar.
Can you count how many VS Code extensions you have right now?
Me: A whooping 56.
If you’re finding VS Code getting slower and more power-hungry with time, this number could well be the reason.
Because EVERY new extension added increases the app’s memory and CPU usage.
Coding is already challenging enough; Nobody need contend with this:
So we need to keep this number as low as possible to minimize this resource usage; ad also stopping these extensions from clashing with one another or with native functionality.
And you know, there’s a significant number of extensions in the Marketplace that provide functionality VSCode already has built-in.
Usually they were made when the feature wasn’t added yet; but once that happened they became largely redundant additions.
So below, I cover a list of these integrated VSCode features and extensions that provide them. Uninstalling these now dispensable extensions will increase your editor’s performance and efficiency.
I’ll be listing settings that control the behavior of these features. If you don’t know how to change settings, this guide will help.
The path autocompletion feature provides a list of files in your project to choose from when importing a module or linking a resource in HTML.
Extensions for this
These extensions add the path autocompletion feature to VSCode:
Path IntelliSense (12.5M+ downloads): “Visual Studio Code Plugin that autocompletes filenames”.
Path Autocomplete (1.7M+ downloads): “Provides path completion for Visual Studio Code and VS Code for the web”.
But feature already built in
VS Code already has native path autocompletion.
When I type in a filename to import (typically when the opening quote is typed), a list suggested project files shows up for me to quickly choose from.
3. Snippets for HTML and CSS
These extensions help you save time by adding common HTML and CSS snippets using abbreviations you can easily recall.
Extensions for this
These extensions bring convenient HTML and/or CSS snippets to VSCode:
HTML Snippets (10.1M+ downloads): “Full HTML tags including HTML5 snippets”.
HTML Boilerplate (3.2M+ downloads): “A basic HTML5 boilerplate snippet generator”.
CSS Snippets (225K+ downloads): “Shorthand snippets for CSS”.
But feature already built-in
Emmet is a built-in VSCode feature that provides HTML and CSS snippets like these extensions. As you’ll see in the official VSCode Emmet guide, it’s enabled by default in html, haml, pug, slim, jsx, xml, xsl, css, scss, sass, less, and stylus files.
Comprehensive to say the least.
When you start typing an Emmet abbreviation, a suggestion will pop up with auto-completion options; You’ll also see a preview of the expansion as you type in the VSCode’s suggestion documentation fly-out (if it is open).
Notice how similar the abbreviations are to CSS selectors. It’s by design; as stated on the official website, Emmet syntax is inspired by CSS selectors.
4. Bracket pair colorization
Bracket pair coloring is a popular syntax highlighting feature that colors brackets differently based on their order.
It makes it easier to identify scope and helps in writing expressions that involve many parentheses, such as single-statement function composition.
Extensions for this
Until VSCode had it built-in, these extensions helped enable the feature in the editor:
Bracket Pair Colorizer 2 (6.1M+ downloads): “A customizable extension for colorizing matching brackets”. It has now been deprecated.
Rainbow Brackets: (1.9M downloads): “A rainbow brackets extension for VS Code”.
I noticed Colorizer 2 has actually been deprecated since 2021 — wasn’t enough to stop millions from installing it every single year till date.
But feature already built in
After seeing the demand for bracket pair coloring and the performance issues involved in adding the feature as an extension, the VSCode team decided to integrate it into the editor.
In this blog, they say that the native bracket pair coloring feature is more than 10,000 times faster than Bracket Pair Colorizer 2.
Here’s the setting to enable/disable bracket pair colorization.
Editor > Bracket Pair Colorization: “Controls whether bracket pair colorization is enabled or not”. It is true by default, there’s been some debate about whether this should be the case here.
You can enable this by adding the following to your settings.json
There is a maximum of 6 colors that can be used for successive nesting levels. Although each theme will have its maximum. For example, the Dracula theme has 6 colors by default, but the One Dark Pro theme has only 3.
Nevertheless, you can customize the bracket colors for any theme with the workbench.colorCustomizations setting.
We specify the name of the theme in square brackets ([ ]), then we assign values to the relevant properties. The editorBracketHighlight.foregroundN property sets the color of the Nth set of brackets, and 6 is the maximum.
Now this will be the bracket pair colorization for One Dark Pro:
5. Auto importing of modules
With an auto-importing feature, when a function, variable, or some other member of a module is referenced in a file, the module is automatically imported into the file, saving time and effort.
If the module files are moved, the feature will help automatically update them.
Extensions for this
Here are some of the most popular extensions providing the feature for VSCode users:
Auto Import (3.8M downloads): “Automatically finds, parses, and provides code actions and code completion for all available imports. Works with Typescript and TSX”.
Move TS (810K downloads): “extension for moving typescript files and folders and updating relative imports in your workspace”.
But feature already built in
You can enable or disable auto-importing modules in VSCode with the following settings.
JavaScript > Suggest: Auto Imports: “Enable/disable auto import suggestions”. It is true by default.
TypeScript > Suggest: Auto Imports: “Enable/disable auto import suggestions”. It is true by default.
JavaScript > Update Imports on File Move: “Enable/disable automatic updating of import paths when you rename or move a file in VS Code”. The default value is prompt, meaning that a dialog is shown to you, asking if you want to update the imports of the moved file. Setting it to alwayswill cause the dialog to be skipped, and never will turn off the feature entirely.
TypeScript > Update Imports on File Move: “Enable/disable automatic updating of import paths when you rename or move a file in VS Code”. Like the previous setting, it has possible values of prompt, always, and never, and the default is prompt.
You can control these settings with these settings.json properties:
This will remove unused import statements and arrange import statements with absolute paths on top, providing a hands-off way to clean up your code.
Final thoughts
These extensions might have served a crucial purpose in the past, but not anymore for the most part, as much of the functionality they provide has been added as built-in VSCode features. Remove them to reduce the bloat and increase the efficiency of Visual Studio Code.
They claim it’s the silver bullet for all software creation, a miraculous tech outperforming every other AI model and handling real-world programming with ease.
With recent news of Nvidia CEO, Jensen Huang, confidently predicting the impending death of coding, surely this Devin AI thing must be the first nail to go in the coffin.
Oh no… before jumping on the bandwagon we need to take a closer look at the deception behind this supposed game-changer.
The first glaring issue is the lack of transparency surrounding Devin AI’s performance metrics.
Sure, they claim it’s superior, but how did they arrive at these numbers? And where’s the proof? There’s a conspicuous absence of generated source code to back up their claims.
Without this crucial evidence you can’t take their word at face value.
Can Devin AI really make a meaningful impact in a real-world repository? Doubtful. And what about limitations? Not a word. It’s as if they want us to believe Devin AI is flawless, without a single drawback.
The demos provided by Devin AI are suspect at best; They showcase its abilities but conveniently omit crucial details. Ever notice how they never revealed the prompts inputted by the user?
If you pause the videos and examine the timestamps, you’ll find it takes hours, not the mere five minutes they lead you to believe. It’s a smoke and mirrors act designed to dazzle without substance.
And what about the demos themselves? They’re basic, rudimentary at best. Many of the problems showcased are nothing more than following a tutorial, some of which even included code snippets.
Hype over competence.
Perhaps the most concerning aspect is the lack of public testing. If Devin AI truly lives up to the hype, why not let the public put it through its paces?
The reluctance to release it for testing raises red flags and hints at a possible cash grab scheme. Business may well soon find themselves disillusioned with promises that fail to materialize.
Trusting AI blindly is a path to failure.
Even if Devin AI does possess remarkable capabilities, it’s important to remember that code still requires human understanding and review to be acceptable. Software engineering is a nuanced field with countless variables; How can an AI know it is correct when its idea of correctness is bound by its training data?
If you think AI can replace developers so easily, then you probably missing the whole point of why we code. Coding at it’s core, is not about typing and compiling. It’s not even about creating apps or websites.
Coding is about specifying the requirements of a system with zero ambiguity. It’s about expressing the solution to a problem with absolute precision.
When you type in a prompt to ChatGPT with all the vivid descriptions and (hopefully) expressive constraints, you are coding.
The difference now is the glaring ambiguity of natural language; the lack of certainty of getting exactly what you want from the AI 100% of the time. That’s why you can refine a prompt dozens of times and have absolutely nothing to show for it.
So AI can only be as good at generating code as the instructions it’s given. And describing the software you want with precision has always been the greatest challenge in software development.
If Devin AI can compel users to provide enough definitions, then perhaps it has potential. But until then, it remains an overhyped tool with limited utility.
AI’s role in programming is similar to the evolution of programming languages. As languages have progressed, programming has become more accessible. But has this led to fewer programmers? No. Instead, it has expanded the reach of programming, leading to more innovation and productivity.
Likewise AI-supported coding will enhance productivity, not replace developers. These AI models are essentially sophisticated search engines trained on vast amounts of data. They excel at common tasks but falter when faced with specific or innovative challenges. They lack the creativity and problem-solving abilities inherent in human developers.
Once again let’s not forget about reliability; AI may churn out code, but isn’t always accurate; deploying AI in critical applications without human oversight is a recipe for disaster. Developers are essential for identifying and correcting errors to ensure the integrity and functionality of the software.
Devin AI may have its uses but it’s far from the panacea it’s been made out to be. As software engineers we should embrace innovation but remain skeptical of overhyped technologies. After all, it’s our expertise and ingenuity that will continue to drive progress in the field, not flashy AI gimmicks.
With the immutable swap worked out, our game plan is pretty straightforward:
For each item i in 0..n, immutably select an index in 0..i to swap with i for each i in 0..n
Loop through the array again and immutably swap each element with its assigned swapping pair.
For #1 we can easily use map() to create an array with the new random positions for every index:
JavaScriptCopied!
const getShuffledPosition = (arr) => {
return [...Array(arr.length)].map((_, i) =>
Math.floor(Math.random() * (i + 1))
);
};
/* [0, 2, 0, 1]
swap item at:
1. index 0 with index 0
2. index 1 with index 2
3. index 2 with index 0
4. index 3 with index 1
*/
getShuffledPosition(['🔵', '🔴', '🟡', '🟢']);
getShuffledPosition(['🔵', '🔴', '🟡', '🟢']); // [0, 1, 1, 3]
getShuffledPosition(['🔵', '🔴', '🟡', '🟢']); // [0, 0, 2, 1]
What about #2?
We’re outputting an array, but we can’t use map again because the transformation at each step depends on the full array and not just the current element.
Just like you can always write a recursive algorithm as a loop, you can write every imperative iteration as a brilliant single-statement chain of array methods.