Before starting I have to say that I come from a design background and not so long ago I didn’t knew anything about bitwise operations, in fact I didn’t even knew that it existed, the content described on this post should be trivial for developers coming from a computer science background or low-level languages…
The intention of this post is not to teach what each bitwise operator does, in fact I’m going to explain how to use it without telling what it does since I think it may be easier to understand. The main reason for writing this post is because I had to explain this technique to a couple of different friends over the past years (or at least I tried…) and also because I believe that most front-end developers don’t know about it.
I think I’ve learned it around 3 years ago when I was planing to code a multiplayer RPG game with a couple of friends and was doing some research about ways to optimize data transfer, that was probably the first time I saw a real use for bitwise operations on high-level programing besides splitting color channels…
A common use for this technique is to store multiple settings that can be mixed and matched together, it can help reduce the amount of memory / bandwidth required to store / process / transfer the information and it also simplify some operations… PHP uses this technique for the error reporting settings. – if you think about it on an abstract way, every single operation that a computer does is a series of bitwise operations, but that isn’t important right now, the important is to understand how to use it on a high-level context and when…
I’m not going to explain what each bitwise operator does, I believe that just looking at the example may be enough to understand what is going on and trying to explain bitwise operators may be an overhead since you don’t need to know that much to use it on this specific context.
//--- Masks ---// var vote = 1 << 0; //1 var add = 1 << 1; //2 var remove = 1 << 2; //4 var manage = 1 << 3; //8 var comment = 1 << 4; //16 var publish = 1 << 25; //33554432 //--- Sets ---// var user1 = vote | remove | manage; //can "vote", "remove", "manage" var user2 = user1 | publish; //all `user1` plus "publish" var user3 = user2 ^ manage; //all `user2` minus "manage" //--- Matches ---// console.log("USER 1 : "+ user1); //13 console.log(user1 & vote); //1 : TRUE console.log(user1 & add); //0 : FALSE console.log(user1 & remove); //4 : TRUE console.log(user1 & manage); //8 : TRUE console.log(user1 & comment); //0 : FALSE console.log(user1 & publish); //0 : FALSE console.log("USER 2 : "+ user2); //33554445 console.log(user2 & vote); //1 : TRUE console.log(user2 & add); //0 : FALSE console.log(user2 & remove); //4 : TRUE console.log(user2 & manage); //8 : TRUE console.log(user2 & comment); //0 : FALSE console.log(user2 & publish); //33554432 : TRUE console.log("USER 3 : "+ user3); //33554437 console.log(user3 & vote); //1 : TRUE console.log(user3 & add); //0 : FALSE console.log(user3 & remove); //4 : TRUE console.log(user3 & manage); //0 : FALSE console.log(user3 & comment); //0 : FALSE console.log(user3 & publish); //33554432 : TRUE
On the example above the variables
vote, add, remove, manage, comment, publish are flags. A flag is a "kind of ID" (in fact it is an integer) that represents the position of a specific boolean value. A flag value should be 2 power of N where N is 0...31 (ie. 1, 2, 16, 64, 512, 4096...). Flags doesn't need to follow a specific order, they can be mixed/matched as desired and skip as many numbers as you want.
What I'm calling a "set" is in fact a group of booleans. The vars
user1, user2, user3 represent users with different kind of permissions, as you can see it is pretty simple to combine multiple options and create a custom set that only contain the ones you want (for me this is the biggest advantage of using this approach for storing settings). You can store up to 32 boolean values/flags in a single 32-bit number (
1 << 31).
Bitwise operations used to check if the "set" contains a "flag". If the result of the AND bitwise operation between the "set" and "flag" is different than zero it means that the "set" contains the "boolean value".
This is a very useful technique when dealing with a large number of options that needs to be combined/extended or when memory usage is a huge concern (in most cases it isn't), the main drawback of using it is that most developers don't know how to use bitwise operators so it can reduce the code readability/maintainability a lot.
The most important thing is to identify when this is the proper approach for a problem, sometimes it can save a lot of work and make some tasks way easier but most people can get around without never actually using it (for the kind of stuff I usually code it is really uncommon to find a problem that requires it). Don't use it blindly, know why you are doing it and consider different approaches before making your decision.
Remember that you can use the same technique to store any kind of data, not only boolean values, color channels are stored exactly the same way, each color is just an integer that contains multiple integers inside of it:
var color = 0xff00cc; //hexadecimal color (0...16,777,215) var r = color & 0xff0000; //red channel (0...255) var g = color & 0x00ff00; //green channel (0...255) var b = color & 0x0000ff; //blue channel (0...255)
parseInt() are your best friends, if I knew how to use it properly when I was learning bitwise operations everything would be way easier.
parseInt("10101", 2); //21 (21).toString(2); //"10101" parseInt("0xff00ff", 16); //16711935 (16711935).toString(16); //"0xff00ff"