JavaScript: Logic
Page 8
Logic: Bitwise & Triple Equals Operators
Introduction
Learn about triple digit and bitwise operators. Learn to use triple equals signs, exclamation with
double equals signs, bitwise AND, OR, NOT, XOR, Zero Filled Left and Right Shift, Signed Right Shift Operators.
Compare objects with two versus three digit operators
such as ===, !==
versus
==, !=
.
Bitwise operators are represented with &&, ||, ~, ^, >>, <<
and >>>
.
=== Versus ==
If two objects are the same object,
they are equal with ===
.
If two primitives are the same value,
they are equal with both ===
and ==
.
Two different objects, regardless of their value,
will always return false with ===
.
Two different primitives, with the same value
will always return true with either ===
or ==
.
Object Triple Equal Comparison
The difference between comparisons with ===
versus
==
is that the first comparison must match in
both value and object. The second comparison
must only match in value.
The following two examples create two objects, with the same property value. However the green box compares the same objects. The blue box compares similar objects, with the same values, but they're not the same objects.
Therefore the blue box returns false and the green box returns true.
Click For ===
Distinct Objects
function compareSameValueDiffObjects(){ let objThree = new Object(); objThree.n = 3; let objThreeAlso = new Object(); objThreeAlso.n = 3; return (objThree === objThreeAlso); }
Click For ===
Same Objects
function compareSameValueSameObjects(){ let objThree = new Object(); objThree.n = 3; let objThreeAlso = new Object(); objThreeAlso.n = 3; objThreeAlso = objThree; return (objThree === objThreeAlso); }
Primitive Triple Equal Comparison
The following code just compares primitive objects, numbers,
with the same values. The triple equal signs return
true
for different primitive variables,
with the same values.
My conclusion is that triple equal signs only make a difference when comparing objects, not primitives.
Click For ===
Distinct Objects
function compareSameValueDiffNumbers(){ let nA = 7; let nB = 7; return (nA === nB); }
Click For ===
Same Objects
function compareSameValueSameNumbers(){ let nA = 7; let nB = 7; return (nA == nA); }
Symbol Triple Equal Comparison
The following code compares different symbols
with the same values. The triple equal signs return
false
for both.
My conclusion is that Symbols, despite being primitives, are always different objects. Apparently symbols are useful for security because malware cannot create and use fake symbols with the same name and value.
Click For ===
Distinct Symbols Local Versus Global
function compareSameValueDiffSymbols(){ // Local: let sD1 = Symbol('keyname'); // Global: let sD2 = Symbol.for('keyname'); return (sD1 === sD2); }
Click For ===
Same Value & Symbol
compareSameValueDiffSymbolsLocal(){ sD1 = Symbol('d') sD2 = Symbol('d') return (sD1 === sD2); }
!== Versus !=
We can use the triple equal signs above, to learn about the
double not equal sign, !==
.
For two different primitives, with the same values,
!==
should return false.
For two different objects, with the same values,
!==
should return true.
For two different Symbols, with the same values,
!==
should return true.
Object NOT Triple Equal Comparison
The difference between comparisons with !==
versus
!=
is that the first comparison must not match in
either value or object. The second comparison
must not match in value only.
Arrays Triple Not Equal
The following two examples create two arrays, with the
same value for the first entry. However the
green box compares each array, and each array's first entry,
with !=
.
The blue box compares each array, and each array's first entry,
with !==
.
The results are identical because both compare one array's value against another array's value. The second compares one array's first primitive entry against another array's first primitive entry.
Click For !==
Distinct Objects
function tripleNOTEqualCompareNOTSameValueDiffArrays()(){ let a1 = new Array(1); a1[0] = 3; let a2 = new Array(1); a2[0] = 3; // Comparing objects, comparing primitives: return [(a1 !== a2),(a1[0] !== a2[0])]; }
Click For !=
Distinct Objects
function doubleNOTEqualCompareNOTSameValueDiffArrays()(){ let a1 = new Array(1); a1[0] = 3; let a2 = new Array(1); a2[0] = 3; // Comparing objects, comparing primitives: return [(a1 != a2),(a1[0] != a2[0])]; }
Summary: ===, !== Versus ==, !=
Neither operator makes a difference when comparing primitives. The triple digit operators help code determine if you're using the same object in memory. Symbols are the exception. New symbols, despite having the same values, are always different in value and in object (or memory).
Bitwise &, |, ^, ~
Page five provided a brief overview of bitwise operators with JavaScript. This section includes interactive bitwise operations with more detailed discussion.
JavaScript bitwise operations perform on 32 bit numbers. Consider each number as thirty two digits. Each digit's either a zero or a one.
We'll use smaller numbers to display operations. However bear in mind, operations are performed on 32 bits, or eight sets of four bits.
Behind the Scenes Conversion
JavaScript converts 64 bit floating point numbers to 32 bit signed binary integers, for bitwise operations, performs the bitwise operation, then converts the result back to a 64 bit floating point number.
Signed binary numbers include both positive and negative values. If the farthest left bit equals one, then the number is negative. If the farthest left bit equals zero, then the number is positive. However we need to take the twos complement to accomplish signed binary bitwise operations.
& Means AND
The &
compares each bit, in positiion. If both
bits equal one, then a one is returned for the
bit in that position. If either bit is a zero, then
a zero is returned.
Example &
AND two positive numbers. 7 AND 4
equals four because 22
equals four.
In this case 4
behaves
like a mask, to remove every binary digit
from 7
that doesn't match ones.
0111 & 0100 = 0100 0111 0100 ---- 0100
AND two positive numbers. The result of 5 AND 8 equals 0.
In this case 5
and 8
behave
like masks against each other, to remove every binary digit
that doesn't match ones. You might find masks very handy
while developing various applications.
0101 & 1000 = 0000 0101 1000 ---- 0000
Click a Box
The following examples demonstrate applying AND to positive
numbers and positive
binary digits.
Declare two binary digits representing 5
and 8, with 0b0101, 0b1000
.
When using binary numbers keep the number of digits identical.
It's assumed they are positive numbers, regardless of
the left most digit.
You can also allow the JavaScript interpreter to convert positive decimal digits to binary digits, perform AND on those digits, then return a negative result. See the violet box, below. See the binary.js source code.
However twos complement performs accurate binary operations on negative numbers.
7 AND 4
function SevenANDFour(){ return (7 & 4); }
5 AND 8
function FiveANDEight(){ return (0b0101 & 0b1000); }
-7 AND -5
function NegateSevenANDFive(){ return -(7 & 5); }
-7 AND -5
function NegateSevenANDFiveBinary(){ return -(0b111 & 0b101); }
| Means OR
The | compares each bit, in positiion. If either bits equal one, then a one is returned for the bit in that position.
Example |
OR two positive numbers.
They equal seven because
20 equals 1 plus
21 equals 2 plus
22 equals 4.
1 + 2 + 4 = 7
0111 | 0100 = 0111 0111 0100 ---- 0111
^ Means XOR
The ^ compares each bit, in positiion. If the bits are different, the result returns one.
Example ^
XOR two positive numbers. The result equals three.
0111 | 0100 = 0011 0111 0100 ---- 0011
XOR two negative numbers. Assuming we're only using four bit numbers and the left most bit is the signed bit. The the result equals positive one.
1101 | 1111 = 0001 1101 1100 ---- 0001
~ Means NOT
NOT inverts all bits on one number. NOT is a unary operator.
NOT might prove useful in some applications, especially graphics filters. However NOT is most useful in twos complement operations, below.
Perform not on 1101
, which
equals = nine.
The result equals two.
~1101 = 0010
The following, Twos Complement examples include the NOT operation.
Twos Complement
To accomplish bitwise operations on negative numbers, in binary format, we need to take the twos complement. Negative bits are stored like a bitwise NOT, plus a one. Therefore take the opposite digit, from each bit on a binary number, then add one.
Tap the following two boxes to see
that twos complement works for both binary
and decimal numbers, with JavaScript.
I suspect the binary operation, ~d1
,
causes the JavaScript interpreter to convert
all decimal numbers to binary, then back again to decimal.
Twos Complement of Binary Positive 4
Call TwosComplementConvert(0b100)
function TwosComplementConvert(d){ let d2 = d; let d3 = ~d2 + 1; return d3; }
Twos Complement of Decimal Positive 7
Call TwosComplementConvert(7)
function TwosComplementConvert(d){ let d2 = d; let d3 = ~d2 + 1; return d3; }
Twos Complement AND, OR
Now we can AND or OR bitwise operations on negative numbers.
Twos Complement AND:
Twos Complement on 7 AND 3
called as ANDNegateTwoDigits(7,3) AND 111 011 ___ 011 = 3 Negation = -3. function ANDNegateTwoDigits(b1, b2){ let v1 = b1 & b2; let v2 = TwosComplementConvert(v1); // See bottom of page // for debugging output. displayValues(v1,v2,true); return (v2); }
Twos Complement on 4 OR 6.
called as ANDNegateTwoDigits(4,6) AND 100 110 ___ 100 = 4 Negation = -4. function ANDNegateTwoDigits(b1, b2){ let v1 = b1 & b2; let v2 = TwosComplementConvert(v1); displayValues(v1,v2,true); return (v2); }
Twos Complement OR:
Twos Complement on 7 OR 3
called as ORNegateTwoDigits(7,3) OR 111 011 ___ 111 = 7 Negation = -7. function ORNegateTwoDigits(b1, b2){ let v1 = b1 | b2; let v2 = TwosComplementConvert(v1); return (v2); }
Twos Complement on 4 AND 6
called as ORNegateTwoDigits(4,6) OR 100 110 ___ 110 = 6 Negation = -6. function ORNegateTwoDigits(b1, b2){ let v1 = b1 | b2; let v2 = TwosComplementConvert(v1); return (v2); }
Bitwise <<,>>,>>>
Bitwise shifts apply less than and greater than operators. Bit shifts represent moving bits over toward the left or toward the right. The first operand represents the number to modify. The second operand represents the number of bits to shift, either right or left.
Left pointing bit shift operators <<
shift bits to the left.
Right pointing bit shift operators >>>
shift bits to the right.
In both cases, emptied bit locations receive zeros.
Two right pointing bit shift operators >>
,
maintain the sign bit, whether it represents
negative, 1
, or positive, 0
.
Multiply Or Divide
Bitwise operations first convert numbers to integers in binary format. When shifting left you're multiplying by two, for every digit shifted. When shifting right, you're dividing by two, for every digit shifted.
However with divisions, shifting right, your number loses digits, as they fall off to the right. With multiplications, shifting left, your number loses digits, as they fall off to the left, if the resulting value would require more than 32 bits.
Zero Filled Left Shift: <<
<<
this operator represents a zero fill left shift.
In otherwords, every binary digit shifts left by the number of
spaces indicated with the second operand.
The vacated digits, on the right, are filled with zeros.
The farthest left digits disappear.
This usually results in a multiplication by two, for each shift left. If you shift by one, then the left value multiplies by two. If you shift by two, then the left value multiplies by four, etc.
However, when the left most digits fall off
then the value decreases.
If your resulting binary value exceeds 32 bits,
then your result loses left binary digits.
Zero filled Left Shift
called as ShiftLeftZeroFill(7,2) 000111 << 000010 = 011100; Result = 10; function ShiftLeftZeroFill(b1,b2){ return (b1 << b2); }
Zero filled Left Shift
called as ShiftLeftZeroFill(0b1011,0b0001) // 11 times 2: 1011 << 1 = 10110; Result = 22; function ShiftLeftZeroFill(b1,b2){ return (b1 << b2); }
Signed Right Shift >>
Shifts right by pushing copies of the leftmost bit in from the left, and let the rightmost bits fall off.
Signed Bit Shift
The green box, highlights the concept of signed right bit shifts. If the sign bit on the left operand equals one, then it's a negative number. In that case, you're shifting a twos complement number.
In the green box the operation
shifts a negative seven.
That means 0b0111 = +7
becomes
0b1001 = -7
, with
the twos complement operation.
Move the bits over two values to the right.
0b1001
becomes 0b10 = +2
.
Code fills in the sign bit,
giving us negative two.
However signed right shifts are fairly simple when the left most bit is a zero. Then we don't need to convert to two's complement to understand how the shift operates.
Signed Right Shift
called as ShiftRightSigned(7,2) 000111 >> 000010 = 000001; Result = 1 function ShiftRightSigned(b1,b2){ return (b1 >> b2); }
Signed Right Shift
called as ShiftRightSigned(0b1011,0b0001) // Binary numbers // with less than 32bits // seem to be considered positive. // Result = 0b01010. Result = 6. function ShiftRightSigned(b1,b2){ return (b1 >> b2); }
Signed Right Shift
called as ShiftRightSigned(-7,2) // Twos complement -7 // 0b0111 becomes 0b1001. // Shift right twice: 0b10 = 2. // Keep sign bit = -2. Result = -2 function ShiftRightSigned(b1,b2){ return (b1 >> b2); }
Signed Right Shift
called as ShiftRightSigned(0b1011,0b0001) // 11 >> 1 // Again binary numbers, less // than 32 bits in length // are considered positive. 1101 >> 0001 = 0110; Result = 6. function ShiftRightSigned(b1,b2){ return (b1 >> b2); }
Zero Filled Right Shift >>>
The zero filled right shift might be the easiest bit shift to understand. For the most part, you're just dividing a number by multiples of two. The right operand tells us how many multiples of two.
Zero filled Right Shift
called as ShiftRightZeroFill(7,2) 000111 >> 000010 = 00001; Result = 1; function ShiftRightZeroFill(b1,b2){ return (b >> b2); }
Zero filled Left Shift
called as ShiftRightZeroFill(0b1011,0b0001) // 11 divided by 2 // and losing the right most bit. 1011 >> 1 = 10110; Result = 5; function ShiftRightZeroFill(b1,b2){ return (b << b2); }
Debugging Output
Summary
You learned about triple digit operators and bitwise operators.
You compared objects with two versus three digit operators
such as ===, !==
versus
==, !=
.
You learned to use bitwise AND, OR, NOT, XOR, Zero Filled Left and Right Shift, Signed Right Shift.
Bitwise operators are represented with &&, ||, ~, ^, >>, <<
and >>>
.
Learn JavaScript
JavaScript's the foundation of Web developer and Website design skills. This free and unique JavaScript tutorial includes some new or seldom used, but useful features.