Nona Blog

Introduction to boolean logic gates in JavaScript

I recently fumbled my way through the popular https://www.nand2tetris.org/ course, which entails building a computer from its most elementary parts. In short, you create a Tetris game with its own underlying operating system and programming language.

As a Javascript developer some of these concepts were initially quite difficult to wrap my head around, or visualise on a basic level.

Within the course the creators recommend using the HDL (Hardware Description Language) tool they provide as a starting platform for building boolean logic. However, I found this to be a temperamental representation that did not work as I expected. It was also visually unintuitive.

As a response, I decided to build my own version of these building blocks using Javascript, so that it worked in a way that I could easily grasp, even though this would mean further abstraction from the real-life representation.

Before getting into that, I would like to tackle the most fundamental aspect of boolean logic – electricity.

The battery

Let’s begin with the battery. A battery requires both a positive and negative terminal to be connected in order to complete a circuit. Let’s assume our battery is connected to a light that will turn on when both the positive and negative terminals are connected. For the sake of our example let’s say that when this happens (light comes on) it causes our circuit to be in a positive state.

So with that in mind we can assume the following (bear with me here):

  • If both the positive and negative terminals are connected our resulting circuit is positive
  • If only the positive terminal is connected the result is negative
  • If only negative terminal is connected the result is negative
  • Finally, if both the positive and negative are not connected the result is negative

The conclusion here being that only if we connect both the terminals, the result will the positive.

The inverter

An inverter is an electronic device that inverts the state of a circuit passed into it.

In our example this would mean that our result would only be negative if both the positive and negative terminals were connected.

The NAND gate

What we have just built in our example is called a NAND gate and can visually be represented as follows:

If only one (or none) of the terminals are connected the result is positive

If both of the terminals are connected the result is negative

To summarise – our result will only be negative if both terminals are connected otherwise the result will be positive. This is the essence of a NAND logic operator.

In Javascript this can be represented as follows:

const nand = (a, b) => (a === 1 && b === 1 ? 0 : 1)

Here we have a function that takes 2 arguments (a and b). If both “a” and “b” are equal to 1 then output 0, otherwise output 1

So why is this useful to us?

Well, using only a positive and negative state of an electrical current we can prove all types of boolean logic, which form the building blocks of the modern computer system.

At the end of the day, all logic is compiled down to either a 1 or a 0 (binary), with the simplest form of this being the “NAND gate” or a battery connected to an inverter.

Extending the NAND operation

So let’s see what would happen if we actually ran this code:

let result = nand(1, 1)
console.log(result) // logs out 0

result = nand(0, 1)
console.log(result) // logs out 1

result = nand(1, 0)
console.log(result) // logs out 1

result = nand(0, 0)
console.log(result) // logs out 1

This is exactly what we expected.

So what happens if we want to use our NAND gate to invert one of our inputs.

e.g. turn a 1 into a 0 (and visa versa)

The NOT function

The way we can do this is by passing a single input into both parameters of our NAND function.

Well we can define and test this as follows:

const not = (a) => nand(a, a)

let result = not(1)
console.log(result) // outputs 0

result = not(0)
console.log(result) // outputs 1

The AND function

By passing the result of two NAND gates (with a and b as parameters to both) into an additional third NAND gate we can achieve the AND gate logic

const and = (a, b) => nand(nand(a, b), nand(a, b))

let result = and(1, 1)
console.log(result) // logs out 1

result = and(0, 1)
console.log(result) // logs out 0

result = and(1, 0)
console.log(result) // logs out 0

result = and(0, 0)
console.log(result) // logs out 0

What you will notice here is that the result is as if we had never connected the inverter to the circuit in the first place – but let’s try not to overthink this.

The OR function

Similarly to the AND gate we have the OR gate which states:

If A and B are both 0 return 0 otherwise return 1

We can achieve this with a similar implementation to the AND function but with the exceptions of passing two a‘s into the first NAND and two b‘s into the second, finally we pass the result of both into a third NAND.

This can be represented as follows:

const or = (a, b) => nand(nand(a, a), nand(b, b))

let result = or(1, 1)
console.log(result) // logs out 1

result = or(0, 1)
console.log(result) // logs out 1

result = or(1, 0)
console.log(result) // logs out 1

result = or(0, 0)
console.log(result) // logs out 0

The NOR function

For the NOR gate if A and B are both 0 return 1 else return 0

const nor = (a, b) => nand(or(a, b), or(a, b))

let result = or(1, 1)
console.log(result) // logs out 0

result = or(0, 1)
console.log(result) // logs out 0

result = or(1, 0)
console.log(result) // logs out 0

result = or(0, 0)
console.log(result) // logs out 1

The XOR function

If A and B are not equal return 1 else return 0

const xor = (a, b) => or(and(a, not(b)), and(b, not(a)))

let result = or(1, 1)
console.log(result) // logs out 0

result = or(0, 1)
console.log(result) // logs out 1

result = or(1, 0)
console.log(result) // logs out 1

result = or(0, 0)
console.log(result) // logs out 0

For the most part this covers the basic boolean logic functions.

I have added all of the functions here (including some additional more complex ones) – https://gist.github.com/richlloydmiles/32ac7c3146ff8d41decc296329f53a2f

As well as created a visual aid so we can see these gates in action – https://nand-91d08.firebaseapp.com/

Conclusion

There are a few more functions of interest that we can build using our NAND function, including the MUX / DEMUX and array input variations of functions we have already built. In upcoming articles we will be covering these functions as well as arithmetic logic and a memory register, using only the logic we have already built in Javascript.

Nona helps funded businesses accelerate their software projects. If you’d like to soundboard your tech project or your development team, book a consultation with us and we can chat through it! 

Richard Miles

Richard Miles

Fullstack Developer - Nona

Add comment