A bit field is a data structure that holds a sequence of bits. They are sometimes referred to as “flags” and are typically used to store the intermediate state or outcome of a set of operations in embedded devices and microprocessors. They are useful data structures when you want to optimise for space. Bitwise operations also tend to be blazing fast.

Bit fields are suitable for encoding state that is represented by boolean properties, with the meaning of individual bits being determined by the programmer. In javascript we can model a bit field simply with es6 binary primitives and bitwise operators.

I stumbled across bit fields recently through this tweet from Andrew Clark, a member of the ReactJS core team:

React uses a bit field to track side effects. For example, to mark a component as updated:



fiber.effectTag |= Update



Then later to check whether to call componentDidUpdate:



const hasUpdate = fiber.effectTag & Updatehttps://t.co/KjXGFKXvSt pic.twitter.com/JSPQBmhIIn — Andrew Clark (@acdlite) December 17, 2017

The React team are making use of bit fields to track component state within the new fibre architecture of ReactJS! Rather than using React internals as an example lets try with something simpler to learn how to work with a bit field.

Creating our own bit field

Imagine we have an object containing the feature toggle state for an application:

{ autoRefresh : false , sidebarWidgets : true , ticker : false , }

Preserving key order, the above data structure can be encoded in to a bit field of 3 bits with each bit corresponding to a key in the object and it’s value corresponding to the value of the key:

const appFeatureToggleState = 0b010

The app config can now be passed around in the application as a number primitive. I know what you’re thinking - Great, what am I supposed to do with that?!

Operating on bit fields

When working with bit fields, there are a couple of fundamental operations you’ll definitely want:

Setting the value of a bit

Getting the value of a bit

This is done through a combination of masking and bitwise operations. A mask in this context is a another value made up of bits.

Let’s define the bit masks for the feature toggle state example above:

export const defaultState = 0b00000000 export const autoRefresh = 0b00000001 export const sidebarWidgets = 0b00000010 export const ticker = 0b00000100

Setting the value of a bit

We can set the value of a bit using the bitwise OR | and XOR ^ operators in javascript.

The | operator returns a 1 in each bit position for which the corresponding bits of either or both operands are 1s.

The ^ operator returns a 1 in each bit position for which the corresponding bits of either but not both operands are 1s.

Working with our app config example:

import { defaultState , autoRefresh , sidebarWidgets , ticker , } from '/featureFlags.js' const appFeatureToggleConfig = defaultState appFeatureToggleState |= autoRefresh appFeatureToggleState |= ticker appFeatureToggleState |= sidebarWidgets appFeatureToggleState ^= sidebarWidgets

Getting the value of a bit

We can get the value of a bit using the AND & operator. The & operator returns a 1 in each bit position for which the corresponding bits of both operands are 1s.

if ( appFeatureToggleState & ticker === ticker ) { ... doSomething

The reason we have to check that the return value matches the mask is because more than one value can be set in the bitfield at once; so it's not enough to check for a truthy value.

Getting the value of a bit without a pre-defined mask

You can save even more memory by accessing bits without pre-defined masks. This can be done via bitshifting with the left shift << operator. The << operator shifts bits from right to left in 0's. Accessing the same ticker bit as before without the predefined mask:

if ( appFeatureToggleState & ( 1 << 2 ) === ( 1 << 2 ) ) { ... doSomething

Hint: The expression (1 << x) is equivalent to Math.pow(2, x) .

You could also just use the literal binary value:

if ( appFeatureToggleState & 0b00000100 === 0b00000100 ) { ... doSomething

Final thoughts

When using bit fields, we are trading off readability for optimisations in performance/memory usage. It’s advisable to attempt other methods of optimisation before making use of bit fields! - However it's always good to have something in your back pocket for when the time calls. This post also hopefully helps shed some light on the lengths javascript library authors are going to to help shave some bytes off the final bundle size and ensure the best performance possible where needed.

If you are interested in working with bitfields checkout the bitfield library on NPM which supports a variety of data structures as the backing data structure for your bitfield including NodeJS buffers, arrays and even a number representing the max bytes! It also has handy abstractions for getting and setting field values which allows you to avoid the lower level bitshifting operations if you wish ;)

Special thanks to @lammino and @dkatvic for taking the time to review this post.

I'll leave you with a handy table detailing bitwise operators in javascript courtesy of MDN: