Bitmasks in JavaScript

A lot of JavaScript developers will use objects as hash maps. They might take this further and set/unset flags and options for a function. For example:

[js]
function eat(foods) {
if (foods.chicken) { /* … */ }
if (foods.pork) { /* … */ }
if (foods.beef) { /* … */ }
}
[/js]

Unfortunately, objects in JavaScript are not necessarily “hash maps” (even if they’ve been implemented using hash maps). Objects are subject to the rules of prototypical inheritance. Therefore, in order to make the above code safe, we may need to add extra checks:

[js]
function eat(foods) {
if (Object.prototype.toString.call(food) !== "[object Object]") {
return false;
}

if (Object.prototype.hasOwnProperty.call(foods, chicken)) { /* … */ }
if (Object.prototype.hasOwnProperty.call(foods, pork)) { /* … */ }
if (Object.prototype.hasOwnProperty.call(foods, beef)) { /* … */ }
}
[/js]

Assuming you are writing safe code and not leaving things up to chance, you can see how this can quickly become messy.

In my previous blog post, I detailed the JavaScript Enum Pattern. We can combine enumerations with bitmasks to create flags that are faster, less memory-intensive, and easier to write. Due to the prevalence of objects, bitmasking is a technique more common in languages like C++, but they can actually be used in JavaScript.

We can rewrite the above code like this:

[js]
// This is our "enum"
var FOODS = {
CHICKEN: 1,
PORK: 2,
BEEF: 4
};

function eat(foods) {
// Bitwise & operator to check for single flag
if (foods & FOODS.CHICKEN == FOODS.CHICKEN) {
console.log("Ate chicken.");
}
if (foods & FOODS.BEEF == FOODS.BEEF) {
console.log("Ate beef.");
}
if (foods & FOODS.PORK == FOODS.PORK) {
console.log("Ate pork.");
}

// Bitwise & and | operator to check for multiple flags
var chickenAndPork = FOODS.CHICKEN | FOODS.PORK;
if (foods & chickenAndPork == chickenAndPork) {
console.log("Ate chicken and pork.");
}
var everything = FOODS.CHICKEN | FOODS.BEEF | FOODS.PORK;
if (foods & everything == everything) {
console.log("Ate everything!");
}
}

// Use the bitwise | operator to set flags
// Eat chicken and pork
eat(FOODS.CHICKEN | FOODS.PORK);
// Eat beef
eat(FOODS.BEEF);
// Eat everything
eat(FOODS.CHICKEN | FOODS.PORK | FOODS.BEEF);
[/js]

The explanations for how to perform bitmasking can be found in the code comments.

Instead of objects, we are now passing around signed 32-bit integers. The binary bitwise operators (&, ^, |) will always convert their results to a signed 32-bit integer as specified by ECMAScript. It is up to individual JavaScript VMs to decide if they want to apply this optimisation. Even in the worst case, you should hope they would store the result in an IEEE-754 double-precision floating-point format (the default for the JavaScript “number” type). Either way, you can quickly see how this might be more efficient and easier to optimise than JavaScript objects.

We utilise the enumeration “FOODS” to make our bitmasks much easier to read.