You might not need a loop

Ire Aderinokun has written a nifty piece using loops and when we might consider replacing it with another method, say .map() and .filter(). I particularly like what she has to say here:

As I mentioned earlier, loops are a great tool for a lot of cases, and the existence of these new methods doesn’t mean that loops shouldn’t be used at all.

I think these methods are great because they provide code that is in a way self-documenting. When we use the filter() method instead of a for loop, it is easier to understand at first glance what the purpose of the logic is.

However, these methods have very specific use cases and may be overkill if their full value isn’t being used. An example of this is the map() method, which can technically be used to replace almost any arbitrary loop. If in our first example, we only wanted to modify the original articles array and not create a new, modified, amazingArticles, using this method would be unnecessary. It’s important to use the method that suits each scenario, to make sure that we aren’t over- or under-performing.

If you’re interested in digging more into this subject, Adan Giese wrote a great post about the .filter() method a short while ago that’s definitely worth checking out. Oh, and speaking of lots of different ways to approach loops, Chris compiled a list of options for looping over querySelectorAll NodeLists where forEach is just one of many options.

Direct Link to ArticlePermalink

The post You might not need a loop appeared first on CSS-Tricks.

A Bunch of Options for Looping Over querySelectorAll NodeLists

A common need when writing vanilla JavaScript is to find a selection of elements in the DOM and loop over them. For example, finding instances of a button and attaching a click handler to them.

const buttons = document.querySelectorAll(".js-do-thing");
// There could be any number of these! // I need to loop over them and attach a click handler.

There are SO MANY ways to go about it. Let’s go through them.

forEach

forEach is normally for arrays, and interestingly, what comes back from querySelectorAll is not an array but a NodeList. Fortunately, most modern browsers support using forEach on NodeLists anyway.

buttons.forEach((button) => { button.addEventListener('click', () => { console.log("forEach worked"); });
});

If you’re worried that forEach might not work on your NodeList, you could spread it into an array first:

[...buttons].forEach((button) => { button.addEventListener('click', () => { console.log("spread forEach worked"); });
});

But I’m not actually sure if that helps anything since it seems a bit unlikely there are browsers that support spreads but not forEach on NodeLists. Maybe it gets weird when transpiling gets involved, though I dunno. Either way, spreading is nice in case you want to use anything else array-specific, like .map(), .filter(), or .reduce().

A slightly older method is to jack into the array’s natural forEach with this little hack:

[].forEach.call(buttons, (button) => { button.addEventListener('click', () => { console.log("array forEach worked"); });
});

Todd Motto once called out this method pretty hard though, so be advised. He recommended building your own method (updated for ES6):

const forEach = (array, callback, scope) => { for (var i = 0; i < array.length; i++) { callback.call(scope, i, array[i]); }
};

…which we would use like this:

forEach(buttons, (index, button) => { console.log("our own function worked");
});

for .. of

Browser support for for .. of loops looks pretty good and this seems like a super clean syntax to me:

for (const button of buttons) { button.addEventListener('click', () => { console.log("for .. of worked"); });
}

Make an array right away

const buttons = Array.prototype.slice.apply( document.querySelectorAll(".js-do-thing")
);

Now you can use all the normal array functions.

buttons.forEach((button) => { console.log("apply worked");
});

Old for loop

If you need maximum possible browser support, there is no shame in an ancient classic for loop:

for (let i = 0; i < buttons.length; ++i) { buttons[i].addEventListener('click', () => { console.log("for loop worked"); });
}

Libraries

If you’re using jQuery, you don’t even have to bother….

$(".buttons").on("click", () => { console.log("jQuery works");
});

If you’re using a React/JSX setup, you don’t need think about this kind of binding at all.

Lodash has a _.forEach as well, which presumably helps with older browsers.

_.forEach(buttons, (button, key) => { console.log("lodash worked");
});

Poll

Twitter peeps:

Also here’s a Pen with all these options in it.

The post A Bunch of Options for Looping Over querySelectorAll NodeLists appeared first on CSS-Tricks.

Demystifying JavaScript Testing

Many people have messaged me, confused about where to get started with testing. Just like everything else in software, we work hard to build abstractions to make our jobs easier. But that amount of abstraction evolves over time, until the only ones who really understand it are the ones who built the abstraction in the first place. Everyone else is left with taking the terms, APIs, and tools at face value and struggling to make things work.

One thing I believe about abstraction in code is that the abstraction is not magic — it’s code. Another I thing I believe about abstraction in code is that it’s easier to learn by doing.

Imagine that a less seasoned engineer approaches you. They’re hungry to learn, they want to be confident in their code, and they’re ready to start testing. 👍 Ever prepared to learn from you, they’ve written down a list of terms, APIs, and concepts they’d like you to define for them:

  • Assertion
  • Testing Framework
  • The describe/it/beforeEach/afterEach/test functions
  • Mocks/Stubs/Test Doubles/Spies
  • Unit/Integration/End to end/Functional/Accessibility/Acceptance/Manual testing

So…

Could you rattle off definitions for that budding engineer? Can you explain the difference between an assertion library and a testing framework? Or, are they easier for you to identify than explain?

Here’s the point. The better you understand these terms and abstractions, the more effective you will be at teaching them. And if you can teach them, you’ll be more effective at using them, too.

Enter a teach-an-engineer-to-fish moment. Did you know that you can write your own assertion library and testing framework? We often think of these abstractions as beyond our capabilities, but they’re not. Each of the popular assertion libraries and frameworks started with a single line of code, followed by another and then another. You don’t need any tools to write a simple test.

Here’s an example:

const {sum} = require('../math')
const result = sum(3, 7)
const expected = 10
if (result !== expected) { throw new Error(`${result} is not equal to ${expected}`)
}

Put that in a module called test.js and run it with node test.js and, poof, you can start getting confident that the sum function from the math.js module is working as expected. Make that run on CI and you can get the confidence that it won’t break as changes are made to the codebase. 🏆

Let’s see what a failure would look like with this:

Terminal window showing an error indicating -4 is not equal to 10.

So apparently our sum function is subtracting rather than adding and we’ve been able to automatically detect that through this script. All we need to do now is fix the sum function, run our test script again and:

Terminal window showing that we ran our test script and no errors were logged.

Fantastic! The script exited without an error, so we know that the sum function is working. This is the essence of a testing framework. There’s a lot more to it (e.g. nicer error messages, better assertions, etc.), but this is a good starting point to understand the foundations.

Once you understand how the abstractions work at a fundamental level, you’ll probably want to use them because, hey, you just learned to fish and now you can go fishing. And we have some pretty phenomenal fishing polls, uh, tools available to us. My favorite is the Jest testing platform. It’s amazingly capable, fully featured and allows me to write tests that give me the confidence I need to not break things as I change code.

I feel like fundamentals are so important that I included an entire module about it on TestingJavaScript.com. This is the place where you can learn the smart, efficient way to test any JavaScript application. I’m really happy with what I’ve created for you. I think it’ll help accelerate your understanding of testing tools and abstractions by giving you the chance to implement parts from scratch. The (hopeful) result? You can start writing tests that are maintainable and built to instill confidence in your code day after day. 🎣

The early bird sale is going on right now! 40% off every tier! The sale is going away in the next few days so grab this ASAP!

TestingJavaScript.com – Learn the smart, efficient way to test any JavaScript application.

P.S. Give this a try: Tweet what’s the difference between a testing framework and an assertion library? In my course, I’ll not only explain it, we’ll build our own!

The post Demystifying JavaScript Testing appeared first on CSS-Tricks.

How to stop using console.log() and start using your browser’s debugger

Whenever I see someone really effectively debug JavaScript in the browser, they use the DevTools tooling to do it. Setting breakpoints and hopping over them and such. That, as opposed to sprinkling console.log() (and friends) statements all around your code.

Parag Zaveri wrote about the transition and it has clearly resonated with lots of folks! (7.5k claps on Medium as I write).

I know I have hangups about it…

  • Part of debugging is not just inspecting code once as-is; it’s inspecting stuff, making changes and then continuing to debug. If I spend a bunch of time setting up breakpoints, will they still be there after I’ve changed my code and refreshed? Answer: DevTools appears to do a pretty good job with that.
  • Looking at the console to see some output is one thing, but mucking about in the Sources panel is another. My code there might be transpiled, combined, and not quite look like my authored code, making things harder to find. Plus it’s a bit cramped in there, visually.

But yet! It’s so powerful. Setting a breakpoint (just by clicking a line number) means that I don’t have to litter my own code with extra junk, nor do I have to choose what to log. Every variable in local and global scope is available for me to look at that breakpoint. I learned in Parag’s article that you might not even need to manually set breakpoints. You can, for example, have it break whenever a click (or other) event fires. Plus, you can type in variable names you specifically want to watch for, so you don’t have to dig around looking for them. I’ll be trying to use the proper DevTools for debugging more often and seeing how it goes.

While we’re talking about debugging though… I’ve had this in my head for a few months: Why doesn’t JavaScript have log levels? Apparently, this is a very common concept in many other languages. You can write logging statements, but they will only log if the configuration says it should. That way, in development, you can get detailed logging, but log only more serious errors in production. I mention it because it could be nice to leave useful logging statements in the code, but not have them actually log if you set like console.level = "production"; or whatever. Or perhaps they could be compiled out during a build step.

Direct Link to ArticlePermalink

The post How to stop using console.log() and start using your browser’s debugger appeared first on CSS-Tricks.

Why Using reduce() to Sequentially Resolve Promises Works

Writing asynchronous JavaScript without using the Promise object is a lot like baking a cake with your eyes closed. It can be done, but it’s gonna be messy and you’ll probably end up burning yourself.

I won’t say it’s necessary, but you get the idea. It’s real nice. Sometimes, though, it needs a little help to solve some unique challenges, like when you’re trying to sequentially resolve a bunch of promises in order, one after the other. A trick like this is handy, for example, when you’re doing some sort of batch processing via AJAX. You want the server to process a bunch of things, but not all at once, so you space the processing out over time.

Ruling out packages that help make this task easier (like Caolan McMahon’s async library), the most commonly suggested solution for sequentially resolving promises is to use Array.prototype.reduce(). You might’ve heard of this one. Take a collection of things, and reduce them to a single value, like this:

let result = [1,2,5].reduce((accumulator, item) => { return accumulator + item;
}, 0); // <-- Our initial value. console.log(result); // 8

But, when using reduce() for our purposes, the setup looks more like this:

let userIDs = [1,2,3]; userIDs.reduce( (previousPromise, nextID) => { return previousPromise.then(() => { return methodThatReturnsAPromise(nextID); });
}, Promise.resolve());

Or, in a more modern format:

let userIDs = [1,2,3]; userIDs.reduce( async (previousPromise, nextID) => { await previousPromise; return methodThatReturnsAPromise(nextID);
}, Promise.resolve());

This is neat! But for the longest time, I just swallowed this solution and copied that chunk of code into my application because it “worked.” This post is me taking a stab at understanding two things:

  1. Why does this approach even work?
  2. Why can’t we use other Array methods to do the same thing?

Why does this even work?

Remember, the main purpose of reduce() is to “reduce” a bunch of things into one thing, and it does that by storing up the result in the accumulator as the loop runs. But that accumulator doesn’t have to be numeric. The loop can return whatever it wants (like a promise), and recycle that value through the callback every iteration. Notably, no matter what the accumulator value is, the loop itself never changes its behavior — including its pace of execution. It just keeps rolling through the collection as fast as the thread allows.

This is huge to understand because it probably goes against what you think is happening during this loop (at least, it did for me). When we use it to sequentially resolve promises, the reduce() loop isn’t actually slowing down at all. It’s completely synchronous, doing its normal thing as fast as it can, just like always.

Look at the following snippet and notice how the progress of the loop isn’t hindered at all by the promises returned in the callback.

function methodThatReturnsAPromise(nextID) { return new Promise((resolve, reject) => { setTimeout(() => { console.log(`Resolve! ${dayjs().format('hh:mm:ss')}`); resolve(); }, 1000); });
} [1,2,3].reduce( (accumulatorPromise, nextID) => { console.log(`Loop! ${dayjs().format('hh:mm:ss')}`); return accumulatorPromise.then(() => { return methodThatReturnsAPromise(nextID); });
}, Promise.resolve());

In our console:

"Loop! 11:28:06" "Loop! 11:28:06" "Loop! 11:28:06" "Resolve! 11:28:07" "Resolve! 11:28:08" "Resolve! 11:28:09"

The promises resolve in order as we expect, but the loop itself is quick, steady, and synchronous. After looking at the MDN polyfill for reduce(), this makes sense. There’s nothing asynchronous about a while() loop triggering the callback() over and over again, which is what’s happening under the hood:

while (k < len) { if (k in o) { value = callback(value, o[k], k, o); } k++;
}

With all that in mind, the real magic occurs in this piece right here:

return previousPromise.then(() => { return methodThatReturnsAPromise(nextID)
});

Each time our callback fires, we return a promise that resolves to another promise. And while reduce() doesn’t wait for any resolution to take place, the advantage it does provide is the ability to pass something back into the same callback after each run, a feature unique to reduce(). As a result, we’re able build a chain of promises that resolve into more promises, making everything nice and sequential:

new Promise( (resolve, reject) => { // Promise #1 resolve();
}).then( (result) => { // Promise #2 return result;
}).then( (result) => { // Promise #3 return result;
}); // ... and so on!

All of this should also reveal why we can’t just return a single, new promise each iteration. Because the loop runs synchronously, each promise will be fired immediately, instead of waiting for those created before it.

[1,2,3].reduce( (previousPromise, nextID) => { console.log(`Loop! ${dayjs().format('hh:mm:ss')}`); return new Promise((resolve, reject) => { setTimeout(() => { console.log(`Resolve! ${dayjs().format('hh:mm:ss')}`); resolve(nextID); }, 1000); });
}, Promise.resolve());

In our console:

"Loop! 11:31:20" "Loop! 11:31:20" "Loop! 11:31:20" "Resolve! 11:31:21" "Resolve! 11:31:21" "Resolve! 11:31:21"

Is it possible to wait until all processing is finished before doing something else? Yes. The synchronous nature of reduce() doesn’t mean you can’t throw a party after every item has been completely processed. Look:

function methodThatReturnsAPromise(id) { return new Promise((resolve, reject) => { setTimeout(() => { console.log(`Processing ${id}`); resolve(id); }, 1000); });
} let result = [1,2,3].reduce( (accumulatorPromise, nextID) => { return accumulatorPromise.then(() => { return methodThatReturnsAPromise(nextID); });
}, Promise.resolve()); result.then(e => { console.log("Resolution is complete! Let's party.")
});

Since all we’re returning in our callback is a chained promise, that’s all we get when the loop is finished: a promise. After that, we can handle it however we want, even long after reduce() has run its course.

Why won’t any other Array methods work?

Remember, under the hood of reduce(), we’re not waiting for our callback to complete before moving onto the next item. It’s completely synchronous. The same goes for all of these other methods:

But reduce() is special.

We found that the reason reduce() works for us is because we’re able to return something right back to our same callback (namely, a promise), which we can then build upon by having it resolve into another promise. With all of these other methods, however, we just can’t pass an argument to our callback that was returned from our callback. Instead, each of those callback arguments are predetermined, making it impossible for us to leverage them for something like sequential promise resolution.

[1,2,3].map((item, [index, array]) => [value]);
[1,2,3].filter((item, [index, array]) => [boolean]);
[1,2,3].some((item, [index, array]) => [boolean]);
[1,2,3].every((item, [index, array]) => [boolean]);

I hope this helps!

At the very least, I hope this helps shed some light on why reduce() is uniquely qualified to handle promises in this way, and maybe give you a better understanding of how common Array methods operate under the hood. Did I miss something? Get something wrong? Let me know!

The post Why Using reduce() to Sequentially Resolve Promises Works appeared first on CSS-Tricks.

Moving Backgrounds With Mouse Position

Let’s say you wanted to move the background-position on an element as you mouse over it to give the design a little pizzazz. You have an element like this:

<div class="module" id="module"></div>

And you toss a background on it:

.module { background-image: url(big-image.jpg);
}

You can adjust the background-position in JavaScript like this:

const el = document.querySelector("#module"); el.addEventListener("mousemove", (e) => { el.style.backgroundPositionX = -e.offsetX + "px"; el.style.backgroundPositionY = -e.offsetY + "px";
});

See the Pen Move a background with mouse by Chris Coyier (@chriscoyier) on CodePen.

Or, you could update CSS custom properties in the JavaScript instead:

const el = document.querySelector("#module"); el.addEventListener("mousemove", (e) => { el.style.setProperty('--x', -e.offsetX + "px"); el.style.setProperty('--y', -e.offsetY + "px");
});
.module { --x: 0px; --y: 0px; background-image: url(large-image.jpg); background-position: var(--x) var(--y);
}

See the Pen Move a background with mouse by Chris Coyier (@chriscoyier) on CodePen.

Here’s an example that moves the background directly in JavaScript, but with a transition applied so it slides to the new position rather than jerking around the first time you enter:

See the Pen Movable Background Ad by Chris Coyier (@chriscoyier) on CodePen.

Or, you could move an actual element instead (rather than the background-position). You’d do this if there is some kind of content or interactivity on the sliding element. Here’s an example of that, which sets CSS custom properties again, but then actually moves the element via a CSS translate() and a calc() to temper the speed.

See the Pen Hotjar Moving Heatmap Ad by Chris Coyier (@chriscoyier) on CodePen.

I’m sure there are loads of other ways to do this — a moving SVG viewBox, scripts controlling a canvas, webGL… who knows! If you have some fancier ways to handle this, link ’em up in the comments.

The post Moving Backgrounds With Mouse Position appeared first on CSS-Tricks.

New mobile Chrome feature would disable scripts on slow connections

This is a possible upcoming feature for mobile Chrome:

If a Data Saver user is on a 2G-speed or slower network according to the NetInfo API, Chrome disables scripts and sends an intervention header on every resource request. Users are shown a UI at the bottom of the screen indicating the page has been modified to save data. Users can enable scripts on the page by tapping “Show original” in the UI.

And the people shout: progressive enhancement!

Jeremy Keith:

An excellent idea for people in low-bandwidth situations: automatically disable JavaScript. As long as the site is built with progressive enhancement, there’s no problem (and if not, the user is presented with the choice to enable scripts).

Power to the people!

George Burduli reports:

This is huge news for developing countries where mobile data packets may cost a lot and are not be affordable to all. Enabling NoScript by default will make sure that users don’t burn through their data without knowledge. The feature will probably be available in the Chrome 69, which will also come with the new Material Design refresh.

The post New mobile Chrome feature would disable scripts on slow connections appeared first on CSS-Tricks.

Level up your .filter game

.filter is a built-in array iteration method that accepts a predicate which is called against each of its values, and returns a subset of all values that return a truthy value.

That is a lot to unpack in one statement! Let’s take a look at that statement piece-by-piece.

  • “Built-in” simply means that it is part of the language—you don’t need to add any libraries to get access to this functionality.
  • “Iteration methods” accept a function that are run against each item of the array. Both .map and .reduce are other examples of iteration methods.
  • A “predicate” is a function that returns a boolean.
  • A “truthy value” is any value that evaluates to true when coerced to a boolean. Almost all values are truthy, with the exceptions of: undefined, null, false, 0, NaN, or "" (empty string).

To see .filter in action, let’s take a look at this array of restaurants.

const restaurants = [ { name: "Dan's Hamburgers", price: 'Cheap', cuisine: 'Burger', }, { name: "Austin's Pizza", price: 'Cheap', cuisine: 'Pizza', }, { name: "Via 313", price: 'Moderate', cuisine: 'Pizza', }, { name: "Bufalina", price: 'Expensive', cuisine: 'Pizza', }, { name: "P. Terry's", price: 'Cheap', cuisine: 'Burger', }, { name: "Hopdoddy", price: 'Expensive', cuisine: 'Burger', }, { name: "Whataburger", price: 'Moderate', cuisine: 'Burger', }, { name: "Chuy's", cuisine: 'Tex-Mex', price: 'Moderate', }, { name: "Taquerias Arandina", cuisine: 'Tex-Mex', price: 'Cheap', }, { name: "El Alma", cuisine: 'Tex-Mex', price: 'Expensive', }, { name: "Maudie's", cuisine: 'Tex-Mex', price: 'Moderate', },
];

That’s a lot of information. I’m currently in the mood for a burger, so let’s filter that array down a bit.

const isBurger = ({cuisine}) => cuisine === 'burger';
const burgerJoints = restaurants.filter(isBurger);

isBurger is the predicate, and burgerJoints is a new array which is a subset of restaurants. It is important to note that restaurants remained unchanged from the .filter.

Here is a simple example of two lists being rendered—one of the original restaurants array, and one of the filtered burgerJoints array.

See the Pen .filter – isBurger by Adam Giese (@AdamGiese) on CodePen.

Negating Predicates

For every predicate there is an equal and opposite negated predicate.

A predicate is a function that returns a boolean. Since there are only two possible boolean values, that means it is easy to “flip” the value of a predicate.

A few hours have passed since I’ve eaten my burger, and now I’m hungry again. This time, I want to filter out burgers to try something new. One option is to write a new isNotBurger predicate from scratch.

const isBurger = ({cuisine}) => cuisine === 'burger';
const isNotBurger = ({cuisine}) => cuisine !== 'burger';

However, look at the amount of similarities between the two predicates. This is not very DRY code. Another option is to call the isBurger predicate and flip the result.

const isBurger = ({cuisine}) => cuisine === 'burger';
const isNotBurger = ({cuisine}) => !isBurger(cuisine);

This is better! If the definition of a burger changes, you will only need to change the logic in one place. However, what if we have a number of predicates that we’d like to negate? Since this is something that we’d likely want to do often, it may be a good idea to write a negate function.

const negate = predicate => function() { return !predicate.apply(null, arguments);
} const isBurger = ({cuisine}) => cuisine === 'burger';
const isNotBurger = negate(isBurger); const isPizza = ({cuisine}) => cuisine === 'pizza';
const isNotPizza = negate(isPizza);

You may have some questions.

What is .apply?

MDN:

apply() method calls a function with a given this value, and arguments provided as an array (or an array-like object).

What is arguments?

MDN:

The arguments object is a local variable available within all (non-arrow) functions. You can refer to a function’s arguments within the function by using the arguments object.

Why return an old-school function instead of a newer, cooler arrow function?

In this case, returning a traditional function is necessary because the arguments object is only available on traditional functions.

Returning Predicates

As we saw with our negate function, it is easy for a function to return a new function in JavaScript. This can be useful for writing “predicate creators.” For example, let’s look back at our isBurger and isPizza predicates.

const isBurger = ({cuisine}) => cuisine === 'burger';
const isPizza = ({cuisine}) => cuisine === 'pizza';

These two predicates share the same logic; they only differ in comparisons. So, we can wrap the shared logic in an isCuisine function.

const isCuisine = comparison => ({cuisine}) => cuisine === comparison;
const isBurger = isCuisine('burger');
const isPizza = isCuisine('pizza');

This is great! Now, what if we want to start checking the price?

const isPrice = comparison => ({price}) => price === comparison;
const isCheap = isPrice('cheap');
const isExpensive = isPrice('expensive');

Now the isCheap and isExpensive are DRY, and isPizza and isBurger are DRY—but isPrice and isCuisine share their logic! Luckily, there are no rules for how many functions deep you can return.

const isKeyEqualToValue = key => value => object => object[key] === value; // these can be rewritten
const isCuisine = isKeyEqualToValue('cuisine');
const isPrice = isKeyEqualToValue('price'); // these don't need to change
const isBurger = isCuisine('burger');
const isPizza = isCuisine('pizza');
const isCheap = isPrice('cheap');
const isExpensive = isPrice('expensive');

This, to me, is the beauty of arrow functions. In a single line, you can elegantly create a third-order function. isKeyEqualToValue is a function that returns the function isPrice which returns the function isCheap.

See how easy it is to create multiple filtered lists from the original restaurants array?

See the Pen .filter – returning predicates by Adam Giese (@AdamGiese) on CodePen.

Composing Predicates

We can now filter our array by burgers or by a cheap price… but what if you want cheap burgers? One option is to simply chain to filters together.

const cheapBurgers = restaurants.filter(isCheap).filter(isBurger);

Another option is to “compose” the two predicates into a single one.

const isCheapBurger = restaurant => isCheap(restaurant) && isBurger(restaurant);
const isCheapPizza = restaurant => isCheap(restaurant) && isPizza(restaurant);

Look at all of that repeated code. We can definitely wrap this into a new function!

const both = (predicate1, predicate2) => value => predicate1(value) && predicate2(value); const isCheapBurger = both(isCheap, isBurger);
const isCheapPizza = both(isCheap, isPizza); const cheapBurgers = restaurants.filter(isCheapBurger);
const cheapPizza = restaurants.filter(isCheapPizza);

What if you are fine with either pizza or burgers?

const either = (predicate1, predicate2) => value => predicate1(value) || predicate2(value); const isDelicious = either(isBurger, isPizza);
const deliciousFood = restaurants.filter(isDelicious);

This is a step in the right direction, but what if you have more than two foods you’d like to include? This isn’t a very scalable approach. There are two built-in array methods that come in handy here. .every and .some are both predicate methods that also accept predicates. .every checks if each member of an array passes a predicate, while .some checks to see if any member of an array passes a predicate.

const isDelicious = restaurant => [isPizza, isBurger, isBbq].some(predicate => predicate(restaurant)); const isCheapAndDelicious = restaurant => [isDelicious, isCheap].every(predicate => predicate(restaurant));

And, as always, let’s wrap them up into some useful abstraction.

const isEvery = predicates => value => predicates.every(predicate => predicate(value)); const isAny = predicates => value => predicates.some(predicate => predicate(value)); const isDelicious = isAny([isBurger, isPizza, isBbq]);
const isCheapAndDelicious = isEvery([isCheap, isDelicious]);

isEvery and isAny both accept an array of predicates and return a single predicate.

Since all of these predicates are easily created by higher order functions, it isn’t too difficult to create and apply these predicates based on a user’s interaction. Taking all of the lessons we have learned, here is an example of an app that searches restaurants by applying filters based on button clicks.

See the Pen .filter – dynamic filters by Adam Giese (@AdamGiese) on CodePen.

Wrapping up

Filters are an essential part of JavaScript development. Whether you’re sorting out bad data from an API response or responding to user interactions, there are countless times when you would want a subset of an array’s values. I hope this overview helped with ways that you can manipulate predicates to write more readable and maintainable code.

The post Level up your .filter game appeared first on CSS-Tricks.

Build a state management system with vanilla JavaScript

Managing state is not a new thing in software, but it’s still relatively new for building software in JavaScript. Traditionally, we’d keep state within the DOM itself or even assign it to a global object in the window. Now though, we’re spoiled with choices for libraries and frameworks to help us with this. Libraries like Redux, MobX and Vuex make managing cross-component state almost trivial. This is great for an application’s resilience and it works really well with a state-first, reactive framework such as React or Vue.

How do these libraries work though? What would it take to write one ourselves? Turns out, it’s pretty straightforward and there’s an opportunity to learn some really common patterns and also learn about some useful modern APIs that are available to us.

Before we get started, it’s recommended that you have an intermediary knowledge of JavaScript. You should know about data types and ideally, you should have a grasp of some more modern ES6+ JavaScript features. If not, we’ve got your back. It’s also worth noting that I’m not saying that you should replace Redux or MobX with this. We’re working on a little project to skill-up together and, hey, it could definitely power a small application if you were keeping an eye on the size of your JavaScript payload.

Getting started

Before we dive into code, take a look at what we’re building. It’s a “done list” that adds up the things you’ve achieved today. It’ll update various elements of the UI like magic — all with no framework dependencies. That’s not the real magic though. Behind the scenes, we’ve got a little state system that’s sitting, waiting for instructions and maintaining a single source of truth in a predictable fashion.

View Demo

View Repo

Pretty cool, right? Let’s do some admin first. I’ve put together a bit of a boilerplate so we can keep this tutorial snappy. The first thing you need to do is either clone it from GitHub, or download a ZIP archive and expand it.

Now that you’ve got that going, you’re going to need to run it in a local web server. I like to use a package called http-server for these sort of things, but you can use whatever you want. When you’ve got it running locally, you should see something that looks like this:

The initial state of our boilerplate.

Setting up our structure

Open the root folder in your favorite text editor. This time, for me, the root folder is:

~/Documents/Projects/vanilla-js-state-management-boilerplate/

You should see a structure that looks a bit like this:

/src
├── .eslintrc
├── .gitignore
├── LICENSE
└── README.md

Pub/Sub

Next, open up the src folder and then open up the js folder that lives in there. Make a new folder called lib. Inside that, make a new file called pubsub.js.

The structure of your js directory should look like this:

/js
├── lib
└── pubsub.js

Open up pubsub.js because we’re going to make a little Pub/Sub pattern, which is short for “Publish/Subscribe.” We’re creating the functionality that allows other parts of our application to subscribe to named events. Another part of the application can then publish those events, often with some sort of relevant payload.

Pub/Sub is sometimes hard to grasp, so how about an analogy? Imagine you work in a restaurant and your customers have a starter and a main course. If you’ve ever worked in a kitchen, you’ll know that when the server clears the starters, they let the chefs know which table’s starters are cleared. This is a cue to start on the main courses for that table. In a big kitchen, there are a few chefs who will probably be on different dishes. They’re all subscribed to the cue from the server that the customers have finished their starters, so they know to do their function, which is to prepare the main course. So, you’ve got multiple chefs waiting on the same cue (named event) to do different functions (callback) to each other.

Hopefully thinking of it like that helps it make sense. Let’s move on!

The PubSub pattern loops through all of the subscriptions and fires their callbacks with that payload. It’s a great way of creating a pretty elegant reactive flow for your app and we can do it with only a few lines of code.

Add the following to pubsub.js:

export default class PubSub { constructor() { this.events = {}; }
}

What we’ve got there is a fresh new class and we’re setting this.events as a blank object by default. The this.events object will hold our named events.

After the constructor’s closing bracket, add the following:

subscribe(event, callback) { let self = this; if(!self.events.hasOwnProperty(event)) { self.events[event] = []; } return self.events[event].push(callback);
}

This is our subscribe method. You pass a string event, which is the event’s unique name and a callback function. If there’s not already a matching event in our events collection, we create it with a blank array so we don’t have to type check it later. Then, we push the callback into that collection. If it already existed, this is all the method would do. We return the length of the events collection, because it might be handy for someone to know how many events exist.

Now that we’ve got our subscribe method, guess what comes next? You know it: the publish method. Add the following after your subscribe method:

publish(event, data = {}) { let self = this; if(!self.events.hasOwnProperty(event)) { return []; } return self.events[event].map(callback => callback(data));
}

This method first checks to see if the passed event exists in our collection. If not, we return an empty array. No dramas. If there is an event, we loop through each stored callback and pass the data into it. If there are no callbacks (which shouldn’t ever be the case), it’s all good, because we created that event with an empty array in the subscribe method.

That’s it for PubSub. Let’s move on to the next part!

The core Store object

Now that we’ve got our Pub/Sub module, we’ve got our only dependency for the meat‘n’taters of this little application: the Store. We’ll go ahead and start fleshing that out now.

Let’s first outline what this does.

The Store is our central object. Each time you see @import store from '../lib/store.js, you’ll be pulling in the object that we’re going to write. It’ll contain a state object that, in turn, contains our application state, a commit method that will call our >mutations, and lastly, a dispatch function that will call our actions. Amongst this and core to the Store object, there will be a Proxy-based system that will monitor and broadcast state changes with our PubSub module.

Start off by creating a new directory in your js directory called store. In there, create a new file called store.js. Your js directory should now look like this:

/js
└── lib └── pubsub.js
└──store └── store.js

Open up store.js and import our Pub/Sub module. To do that, add the following right at the top of the file:

import PubSub from '../lib/pubsub.js';

For those who work with ES6 regularly, this will be very recognizable. Running this sort of code without a bundler will probably be less recognizable though. There’s a heck of a lot of support already for this approach, too!

Next, let’s start building out our object. Straight after the import, add the following to store.js:

export default class Store { constructor(params) { let self = this; }
}

This is all pretty self-explanatory, so let’s add the next bit. We’re going to add default objects for state, actions, and mutations. We’re also adding a status element that we’ll use to determine what the object is doing at any given time. This goes right after let self = this;:

self.actions = {};
self.mutations = {};
self.state = {};
self.status = 'resting';

Straight after that, we’ll create a new PubSub instance that will be attached the Store as an events element:

self.events = new PubSub();

Next, we’re going to search the passed params object to see if any actions or mutations were passed in. When the Store object is instantiated, we can pass in an object of data. Included in that can be a collection of actions and mutations that control the flow of data in our store. The following code comes next right after the last line that you added:

if(params.hasOwnProperty('actions')) { self.actions = params.actions;
} if(params.hasOwnProperty('mutations')) { self.mutations = params.mutations;
}

That’s all of our defaults set and nearly all of our potential params set. Let’s take a look at how our Store object keeps track of all of the changes. We’re going to use a Proxy to do this. What the Proxy does is essentially work on behalf of our state object. If we add a get trap, we can monitor every time that the object is asked for data. Similarly with a set trap, we can keep an eye on changes that are made to the object. This is the main part we’re interested in today. Add the following straight after the last lines that you added and we’ll discuss what it’s doing:

self.state = new Proxy((params.state || {}), { set: function(state, key, value) { state[key] = value; console.log(`stateChange: ${key}: ${value}`); self.events.publish('stateChange', self.state); if(self.status !== 'mutation') { console.warn(`You should use a mutation to set ${key}`); } self.status = 'resting'; return true; }
});

What’s happening here is we’re trapping the state object set operations. That means that when a mutation runs something like state.name = 'Foo' , this trap catches it before it can be set and provides us an opportunity to work with the change or even reject it completely. In our context though, we’re setting the change and then logging it to the console. We’re then publishing a stateChange event with our PubSub module. Anything subscribed to that event’s callback will be called. Lastly, we’re checking the status of Store. If it’s not currently running a mutation, it probably means that the state was updated manually. We add a little warning in the console for that to give the developer a little telling off.

There’s a lot going on there, but I hope you’re starting to see how this is all coming together and importantly, how we’re able to maintain state centrally, thanks to Proxy and Pub/Sub.

Dispatch and commit

Now that we’ve added our core elements of the Store, let’s add two methods. One that will call our actions named dispatch and another that will call our mutations called commit. Let’s start with dispatch by adding this method after your constructor in store.js:

dispatch(actionKey, payload) { let self = this; if(typeof self.actions[actionKey] !== 'function') { console.error(`Action "${actionKey} doesn't exist.`); return false; } console.groupCollapsed(`ACTION: ${actionKey}`); self.status = 'action'; self.actions[actionKey](self, payload); console.groupEnd(); return true;
}

The process here is: look for an action and, if it exists, set a status and call the action while creating a logging group that keeps all of our logs nice and neat. Anything that is logged (like a mutation or Proxy log) will be kept in the group that we define. If no action is set, it’ll log an error and bail. That was pretty straightforward, and the commit method is even more straightforward.

Add this after your dispatch method:

commit(mutationKey, payload) { let self = this; if(typeof self.mutations[mutationKey] !== 'function') { console.log(`Mutation "${mutationKey}" doesn't exist`); return false; } self.status = 'mutation'; let newState = self.mutations[mutationKey](self.state, payload); self.state = Object.assign(self.state, newState); return true;
}

This method is pretty similar, but let’s run through the process anyway. If the mutation can be found, we run it and get our new state from its return value. We then take that new state and merge it with our existing state to create an up-to-date version of our state.

With those methods added, our Store object is pretty much complete. You could actually modular-ize this application now if you wanted because we’ve added most of the bits that we need. You could also add some tests to check that everything run as expected. But I’m not going to leave you hanging like that. Let’s make it all actually do what we set out to do and continue with our little app!

Creating a base component

To communicate with our store, we’ve got three main areas that update independently based on what’s stored in it. We’re going to make a list of submitted items, a visual count of those items, and another one that’s visually hidden with more accurate information for screen readers. These all do different things, but they would all benefit from something shared to control their local state. We’re going to make a base component class!

First up, let’s create a file. In the lib directory, go ahead and create a file called component.js. The path for me is:

~/Documents/Projects/vanilla-js-state-management-boilerplate/src/js/lib/component.js

Once that file is created, open it and add the following:

import Store from '../store/store.js'; export default class Component { constructor(props = {}) { let self = this; this.render = this.render || function() {}; if(props.store instanceof Store) { props.store.events.subscribe('stateChange', () => self.render()); } if(props.hasOwnProperty('element')) { this.element = props.element; } }
}

Let’s talk through this chunk of code. First up, we’re importing the Store class. This isn’t because we want an instance of it, but more for checking one of our properties in the constructor. Speaking of which, in the constructor we’re looking to see if we’ve got a render method. If this Component class is the parent of another class, then that will have likely set its own method for render. If there is no method set, we create an empty method that will prevent things from breaking.

After this, we do the check against the Store class like I mentioned above. We do this to make sure that the store prop is a Store class instance so we can confidently use its methods and properties. Speaking of which, we’re subscribing to the global stateChange event so our object can react. This is calling the render function each time the state changes.

That’s all we need to write for that class. It’ll be used as a parent class that other components classes will extend. Let’s crack on with those!

Creating our components

Like I said earlier, we’ve got three components to make and their all going to extend the base Component class. Let’s start off with the biggest one: the list of items!

In your js directory, create a new folder called components and in there create a new file called list.js. For me the path is:

~/Documents/Projects/vanilla-js-state-management-boilerplate/src/js/component/list.js

Open up that file and paste this whole chunk of code in there:

import Component from '../lib/component.js';
import store from '../store/index.js'; export default class List extends Component { constructor() { super({ store, element: document.querySelector('.js-items') }); } render() { let self = this; if(store.state.items.length === 0) { self.element.innerHTML = `<p class="no-items">You've done nothing yet &#x1f622;</p>`; return; } self.element.innerHTML = ` <ul class="app__items"> ${store.state.items.map(item => { return ` <li>${item}<button aria-label="Delete this item">×</button></li> ` }).join('')} </ul> `; self.element.querySelectorAll('button').forEach((button, index) => { button.addEventListener('click', () => { store.dispatch('clearItem', { index }); }); }); }
};

I hope that code is pretty self-explanatory after what we’ve learned earlier in this tutorial, but let’s skim through it anyway. We start off by passing our Store instance up to the Component parent class that we are extending. This is the Component class that we’ve just written.

After that, we declare our render method that gets called each time the stateChange Pub/Sub event happens. In this render method we put out either a list of items, or a little notice if there are no items. You’ll also notice that each button has an event attached to it and they dispatch and action within our store. This action doesn’t exist yet, but we’ll get to it soon.

Next up, create two more files. These are two new components, but they’re tiny — so we’re just going to paste some code in them and move on.

First, create count.js in your component directory and paste the following in it:

import Component from '../lib/component.js';
import store from '../store/index.js'; export default class Count extends Component { constructor() { super({ store, element: document.querySelector('.js-count') }); } render() { let suffix = store.state.items.length !== 1 ? 's' : ''; let emoji = store.state.items.length > 0 ? '&#x1f64c;' : '&#x1f622;'; this.element.innerHTML = ` <small>You've done</small> ${store.state.items.length} <small>thing${suffix} today ${emoji}</small> `; }
}

Looks pretty similar to list, huh? There’s nothing in here that we haven’t already covered, so let’s add another file. In the same components directory add a status.js file and paste the following in it:

import Component from '../lib/component.js';
import store from '../store/index.js'; export default class Status extends Component { constructor() { super({ store, element: document.querySelector('.js-status') }); } render() { let self = this; let suffix = store.state.items.length !== 1 ? 's' : ''; self.element.innerHTML = `${store.state.items.length} item${suffix}`; }
}

Again, we’ve covered everything in there, but you can see how handy it is having a base Component to work with, right? That’s one of the many benefits of Object-orientated Programming, which is what most of this tutorial is based on.

Finally, let’s check that your js directory is looking right. This is the structure of where we’re currently at:

/src
├── js
│ ├── components
│ │ ├── count.js
│ │ ├── list.js
│ │ └── status.js
│ ├──lib
│ │ ├──component.js
│ │ └──pubsub.js
└───── store └──store.js └──main.js

Let’s wire it up

Now that we’ve got our front-end components and our main Store, all we’ve got to do is wire it all up.

We’ve got our store system and the components to render and interact with its data. Let’s now wrap up by hooking up the two separate ends of the app and make the whole thing work together. We’ll need to add an initial state, some actions and some mutations. In your store directory, add a new file called state.js. For me it’s like this:

~/Documents/Projects/vanilla-js-state-management-boilerplate/src/js/store/state.js

Open up that file and add the following:

export default { items: [ 'I made this', 'Another thing' ]
};

This is pretty self-explanatory. We’re adding a default set of items so that on first-load, our little app will be fully interactive. Let’s move on to some actions. In your store directory, create a new file called actions.js and add the following to it:

export default { addItem(context, payload) { context.commit('addItem', payload); }, clearItem(context, payload) { context.commit('clearItem', payload); }
};

The actions in this app are pretty minimal. Essentially, each action is passing a payload to a mutation, which in turn, commits the data to store. The context, as we learned earlier, is the instance of the Store class and the payload is passed in by whatever dispatches the action. Speaking of mutations, let’s add some. In this same directory add a new file called mutations.js. Open it up and add the following:

export default { addItem(state, payload) { state.items.push(payload); return state; }, clearItem(state, payload) { state.items.splice(payload.index, 1); return state; }
};

Like the actions, these mutations are minimal. In my opinion, your mutations should always be simple because they have one job: mutate the store’s state. As a result, these examples are as complex as they should ever be. Any proper logic should happen in your actions. As you can see for this system, we return the new version of the state so that the Store`'s <code>commit method can do its magic and update everything. With that, the main elements of the store system are in place. Let’s glue them together with an index file.

In the same directory, create a new file called index.js. Open it up and add the following:

import actions from './actions.js';
import mutations from './mutations.js';
import state from './state.js';
import Store from './store.js'; export default new Store({ actions, mutations, state
});

All this file is doing is importing all of our store pieces and glueing them all together as one succinct Store instance. Job done!

The final piece of the puzzle

The last thing we need to put together is the main.js file that we included in our index.html page waaaay up at the start of this tutorial. Once we get this sorted, we’ll be able to fire up our browsers and enjoy our hard work! Create a new file called main.js at the root of your js directory. This is how it looks for me:

~/Documents/Projects/vanilla-js-state-management-boilerplate/src/js/main.js

Open it up and add the following:

import store from './store/index.js'; import Count from './components/count.js';
import List from './components/list.js';
import Status from './components/status.js'; const formElement = document.querySelector('.js-form');
const inputElement = document.querySelector('#new-item-field');

So far, all we’re doing is pulling in dependencies that we need. We’ve got our Store, our front-end components and a couple of DOM elements to work with. Let’s add this next bit to make the form interactive, straight under that code:

formElement.addEventListener('submit', evt => { evt.preventDefault(); let value = inputElement.value.trim(); if(value.length) { store.dispatch('addItem', value); inputElement.value = ''; inputElement.focus(); }
});

What we’re doing here is adding an event listener to the form and preventing it from submitting. We then grab the value of the textbox and trim any whitespace off it. We do this because we want to check if there’s actually any content to pass to the store next. Finally, if there’s content, we dispatch our addItem action with that content and let our shiny new store deal with it for us.

Let’s add some more code to main.js. Under the event listener, add the following:

const countInstance = new Count();
const listInstance = new List();
const statusInstance = new Status(); countInstance.render();
listInstance.render();
statusInstance.render();

All we’re doing here is creating new instances of our components and calling each of their render methods so that we get our initial state on the page.

With that final addition, we are done!

Open up your browser, refresh and bask in the glory of your new state managed app. Go ahead and add something like “Finished this awesome tutorial” in there. Pretty neat, huh?

Next steps

There’s a lot of stuff you could do with this little system that we’ve put together. Here are some ideas for taking it further on your own:

  • You could implement some local storage to maintain state, even when you reload
  • You could pull out the front-end of this and have a little state system for your projects
  • You could continue to develop the front-end of this app and make it look awesome. (I’d be really interested to see your work, so please share!)
  • You could work with some remote data and maybe even an API
  • You could take what you’ve learned about Proxy and the Pub/Sub pattern and develop those transferable skills further

Wrapping up

Thanks for learning about how these state systems work with me. The big, popular ones are much more complex and smarter that what we’ve done — but it’s still useful to get an idea of how these systems work and unravel the mystery behind them. It’s also useful to learn how powerful JavaScript can be with no frameworks whatsoever.

If you want a finished version of this little system, check out this GitHub repository. You can also see a demo here.

If you develop on this further, I’d love to see it, so hit me up on Twitter or post in the comments below if you do!

The post Build a state management system with vanilla JavaScript appeared first on CSS-Tricks.

Understanding the Almighty Reducer

I was recently mentoring someone who had trouble with the .reduce() method in JavaScript. Namely, how you get from this:

const nums = [1, 2, 3]
let value = 0 for (let i = 0; i < nums.length; i++) { value += nums[i]
}

…to this:

const nums = [1, 2, 3]
const value = nums.reduce((ac, next) => ac + next, 0)

They are functionally equivalent and they both sum up all the numbers in the array, but there is a bit of paradigm shift between them. Let’s explore reducers for a moment because they’re powerful, and important to have in your programming toolbox. There are literally hundreds of other articles on reducers out there, and I’ll link up some of my favorites at the end.

What is a reducer?

The first and most important thing to understand about a reducer is that it will always only return one value. The job of a reducer is to reduce. That one value can be a number, a string, an array or an object, but it will always only be one. Reducers are really great for a lot of things, but they’re especially useful for applying a bit of logic to a group of values and ending up with another single result.

That’s the other thing to mention: reducers will not, by their nature, mutate your initial value; rather they return something else. Let’s walk over that first example so you can see what’s happening here. The video below explains:

It might be helpful to watch the video to see how the progression occurs, but here’s the code we’re looking at:

const nums = [1, 2, 3]
let value = 0 for (let i = 0; i < nums.length; i++) { value += nums[i]
}

We have our array (1, 2, 3) and the first value each number in the array will be added to (0). We walk through the amount of the array and add them to the initial value.

Let’s try this a little differently:

const nums = [1, 2, 3]
const initialValue = 0 const reducer = function (acc, item) { return acc + item
} const total = nums.reduce(reducer, initialValue)

Now we have the same array, but this time we’re not mutating that first value. Instead, we have an initialValue that will only be used at the start. Next, we can make a function that takes an accumulator 
and an item. The accumulator is the collected value
 returned in the last invocation that informs the function what the next value will be added to. In this case of addition, you can think of it as a snowball rolling down a mountain that eats up each value in its path as it grows in size by every eaten value.

snowball accumulating values

We’ll use .reduce() to apply the function and start from that initial value. This can be shortened with an arrow function:

const nums = [1, 2, 3]
const initialValue = 0 const reducer = (acc, item) => { return acc + item
} const total = nums.reduce(reducer, initialValue)

And then shortened some more! Implicit returns for the win!

const nums = [1, 2, 3]
const initialValue = 0 const reducer = (acc, item) => acc + item const total = nums.reduce(reducer, initialValue)

Now we can apply the function right where we called it, and we can also plop that initial value directly in there!

const nums = [1, 2, 3] const total = nums.reduce((acc, item) => acc + item,

An accumulator can be an intimidating term, so you can think of it like the current state of the array as we’re applying the logic on the callback’s invocations.

The Call Stack

In case it’s not clear what’s happening, let’s log out what’s going on for each iteration. The reduce is using a callback function that will run for each item in the array. IThe following demo will help to make this more clear. I’ve also used a different array ([1, 3, 6]) because having the numbers be the same as the index could be confusing.

See the Pen showing acc, item, return by Sarah Drasner (@sdras) on CodePen.

When we run this, we’ll see this output in the console:

"Acc: 0, Item: 1, Return value: 1" "Acc: 1, Item: 3, Return value: 4" "Acc: 4, Item: 6, Return value: 10"

Here’s a more visual breakdown:

  1. It shows that the accumulator is starting at our initial value, 0
  2. Then we have the first item, which is 1, so our return value is 1 (0 + 1 = 1)
  3. 1 becomes the accumulator on the next invocation
  4. Now we have 1 as the accumulator and 3 is the item aince it is next in the array.
  5. The returned value becomes 4 (1 + 3 = 4)
  6. That, in turn, becomes the accumulator and the next item at invocation is 6
  7. That results in 10 (4 + 6 = 10) and is our final value since 6 is the last number in the array

Simple Examples

Now that we’ve got that under our belt, let’s look at some common and useful things reducers can do.

How many of X do we have?

Let’s say you have an array of numbers and you want to return an object that reports the number of times those numbers occur in the array. Note that this could just as easily apply to strings.

const nums = [3, 5, 6, 82, 1, 4, 3, 5, 82] const result = nums.reduce((tally, amt) => { tally[amt] ? tally[amt]++ : tally[amt] = 1 return tally
}, {}) console.log(result)

See the Pen simplified reduce by Sarah Drasner (@sdras) on CodePen.

Wait, what did we just do?

Initially, we have an array and the object we’re going to put its contents into. In our reducer, we ask: does this item exist? If so, let’s increment it. If not, add it and set it to 1. At the end, please return the tally count of each item. Then, we run the reduce function, passing in both the reducer and the initial value.

Take an array and turn it into an object that shows some conditions

Let’s say we have an array and we want to create an object based on a set of conditions. Reduce can be great for this! Here, we want to create an object out of any instance of a number contained in the array and show both an odd and even version of this number. If the number is already even or odd, then that’s what we’ll have in the object.

const nums = [3, 5, 6, 82, 1, 4, 3, 5, 82] // we're going to make an object from an even and odd
// version of each instance of a number
const result = nums.reduce((acc, item) => { acc[item] = { odd: item % 2 ? item : item - 1, even: item % 2 ? item + 1 : item } return acc
}, {}) console.log(result)

See the Pen simplified reduce by Sarah Drasner (@sdras) on CodePen.

This will shoot out the following output in the console:

1:{odd: 1, even: 2}
3:{odd: 3, even: 4}
4:{odd: 3, even: 4}
5:{odd: 5, even: 6}
6:{odd: 5, even: 6}
82:{odd: 81, even: 82}

OK, so what’s happening?

As we’re going through every item in the array, we create a property for even and odd, and based on an inline condition with a modulus operator, we’ll either store the number or increment it by 1. The modulus operator is really good for this because it can quickly check for even or odd — if it’s divisible by two, it’s even, if not, it’s odd.

Other resources

At the top, I mentioned other posts out there that are handy resources to get more familiar with the role of reducers. Here are a few of my favorites:

  • The MDN documentation is wonderful for this. Seriously, it’s one of their best posts, IMO. They also describe in a bit more detail what happens if you don’t provide an initial value, which we didn’t cover in this post.
  • Daniel Shiffman is always amazing at explaining things on Coding Train.
  • A Drip of JavaScript does a good job, too.

The post Understanding the Almighty Reducer appeared first on CSS-Tricks.