Preface: This is my first article in nuggets, the theme comes from a discussion about bitwise operators and logical operators with netizens some time ago. Felt the need to share for the first time with the Nuggets. Although I have always been in the habit of taking notes and code words on the Internet, but it is the first time to share online, so my writing style is hard to avoid. I hope you can understand. Secondly, if the content is wrong, please point out, thank you!
Self-testing of bit operations:
Start with an appetizer to help warm up. If more than half of the questions are wrong, you need the passage.
var num1 = 1 & 0;
console.log(num1);
var num2 = 'string' & 1;
console.log(num2);
var num3 = true & 1;
console.log(num3);
var num4 = undefined | false;
console.log(num4);
var num5 = undefined | true;
console.log(num5);
var num6 = 23 & 5;
console.log(num6);
var num7 = 23 | 5;
console.log(num7);
var num8 = 8 << 'string';
console.log(num8);
var num9 = ({}) && 3;
console.log(num9);
var num10 = ({}) & 3;
console.log(num10);
var num11 = ({}) || 3;
console.log(num11);
var num12 = ({}) | 3;
console.log(num12);
Copy the code
As for the answers with explanations, please save them for later in the article.
What is a bit operation:
Bitwise operators are used at the most basic level (that is, to manipulate values by the bits that represent them in memory). All values in ECMAScript are stored in ieEE-754 64-bit format, but bitwise operators do not directly manipulate 64-bit values. Instead, the 64-bit value is converted to a 32-bit integer, the operation is performed, and the result is converted to 64-bit.
For signed integers, the last 31 of the 32 bits are used to represent the value of the integer, and the first bit represents the symbol of the value: 0 for a positive number and 1 for a negative number. A positive number
Positive numbers are stored in pure binary format, where each of the 31 bits represents a power of two (and one is a sign bit). The first digit represents 2º, the second 2¹, the third 2², and so on. Bits that are not used are 0 (that is, ignored).
Negative Numbers Negative numbers are also stored in binary code, but in the format of binary complement. To compute the binary complement of a numeric value (i.e. to find the binary code of a negative number), the following three steps are required: ①. Find the binary of the absolute value of this number (for example, if you want the binary complement of -18, find the binary of 18 first). (2). Find the binary inverse code, that is, replace 0 with 1, replace 1 with 0. ③. The resulting binary inverse code +1.
// The binary code of 18 is 00000000 00000000 00000000 00010010. 1111111111111111111111101101 // the binary inverse +1:11 111111111111111111111111111111101110Copy the code
The underlying processing of bitwise operators:
According to the ECMA specification, when bit-operators are used, the following is done at the bottom:
Non-numeric application bitwise operators: The value is converted to a numeric value using the Number() function (automatic), and then the bitwise operation is applied, resulting in a numeric value (type Number).
Numeric application bitwise operators: 64-bit values are converted to 32-bit values, then bitwise operations are performed, and finally 32-bit results are converted to 64-bit values. (Inside JavaScript, values are stored as 64-bit floating-point numbers). This gives the appearance of manipulating 32-bit values, just as binary operations are performed in similar ways in other languages. A side effect of this conversion, however, is that when bits are applied to NaN and Infinity values, both values are treated as zero.
Features of bit operation:
1. The bit operation directly calculates the binary bits. The bit operation directly deals with each bit bit and is a very low-level operation. (Advantage: very fast speed, disadvantage: very not intuitive, many occasions can not be used).
2. The bit operation only applies to integers. If an operand is not an integer, it is automatically converted to an integer and then run.
What are the bit operators:
1. (AND) : &
The combination of the corresponding bits in the binary number in a particular way, if the corresponding bits are all 1, the result is 1. If any of the bits are 0, the result is 0. (Shorthand: two is one)
2. The bitwise OR (OR) : |
| operator with & difference is that if an operand in the corresponding bit is 1, then the result is 1. (Shorthand: there is one)
3. XOR by bit: ^
The result is 1 if there is one and only one 1 for each of the two operation bits, and 0 for all others. (Shorthand: only one 1 equals one)
4. NOT: ~
Note 1: In binary code, to distinguish positive and negative numbers, the highest bit is the sign bit. The sign bit of positive numbers is 0, and the sign bit of negative numbers is 1. What is left is the absolute value of the number, which can be expressed in three forms: original code, inverse code and complement code.
Note 2: The manual rule for non-~ internally uses JavaScript to complement negative numbers (that is, subtract 1 from the number), and then invert the number to decimal and add the negative sign to get the corresponding decimal value.
Example 1: Manual No ~ :
The ~ operator inverts the bits, changing 1 to 0,0 to 1, which is the binary inverse.
Since the first bit (sign bit) in 11111111 11111111 is 1, this number is a negative number.
Internal complement: 111111111111 1111111111 11111111 11111101 Inverse: 00000000 00000000 00000000 00000010 => 2 is expressed in decimal notation plus a negative sign: -2
So minus 1 is minus 2
5. Left shift: <<
The << operator causes all bits of a specified binary number to move to the left a specified number of times by discarding the high bits and filling the low bits with zeros.
Take 1 << 3 as an example:1<<3 => is equivalent to 1×2³ = 8.
Conclusion: The number of digits of any number is equivalent to:
6. Symbols move right: >> (also known as “symbol propagation”)
>> This operator moves the binary bits of the specified operand to the right by the specified number of digits. Bits moved to the right are discarded, and the leftmost bits are copied to fill the left side (this is the biggest difference from unsigned rightwards). Since the new leftmost bit is always the same as before, the sign bit is not changed. That’s why it’s called “symbol propagation.”
Take 4 >> 2 as an example:
7. Unsigned right shift: >>>
>>> This operator moves the first operand to the right by the specified number of digits. Bits moved to the right are discarded, and the left side is filled with zeros (this is the biggest difference from a signed right shift). Because the sign bit becomes zero, the result is always non-negative.
Note: For non-negative numbers, signed and unsigned right shifts always return the same result.
The difference between operators and logical operators (&&, &, | | |) :
&&, & and | | and | in my point of view is completely different symbols (it is).
The calculation results are different: ①.
if(({}) && 3){ console.log("true") }else{ console.log("false"); } / / output is true if (({}) & 3) {the console. The log (" true ")} else {the console. The log (" false "); } / / output results to false if (({}) | | NaN) {the console. The log (" true ")} else {the console. The log (" false "); } / / output is true if (({}) | NaN) {the console. The log (" true ")} else {the console. The log (" false "); } // The output is falseCopy the code
②. Used as an assignment statement:
var result = ({}) && 3; console.log(result); //3 result = ({}) & 3; console.log(result); //0 ------------------------------ var result = ({}) || 3; console.log(result); //{} result = ({}) | 3; console.log(result); / / 3Copy the code
Note: The key difference is that the underlying comparison of the logical operators returns the original value. The bitwise operator returns the value processed by Number().
Different underlying processing logic: | | and & & have the function of the short circuit (i.e. side meet operation requirements, don’t calculate on the other side), and & and | even side to meet the requirements, will calculate again on the other side.
Bitwise operators in JS:
1. Use the & operator to determine the parity of a number:
// Even &1 = 0 // odd &1 = 1 console.log(2&1) // 0 console.log(3&1) // 1Copy the code
2. Use ~, > >, < <, > > >, | to integer:
The console. The log (6.83) ~ ~ / / 6 console. The log (6.83 > > 0) / / 6 console. The log (6.83 < < 0) / / 6 console. The log (6.83 | 0) / / / / 6 >>> Negative numbers cannot be rounded console.log(6.83 >>> 0) // 6Copy the code
3. Use ^ to complete the value swap:
var a = 5
var b = 8
a ^= b
b ^= a
a ^= b
console.log(a) // 8
console.log(b) // 5
Copy the code
4. Use & > > | to complete the RGB values and conversion between hexadecimal color values:
/** * hexadecimal color value to RGB * @param {String} hex hex String * @return {String} RGB color String */ function hexToRGB(hex) {var hexx = hex.replace('#', '0x') var r = hexx >> 16 var g = hexx >> 8 & 0xff var b = hexx & 0xff return `rgb(${r}, ${g}, ${b}) '} /** * RGB color to hexadecimal color * @param {String} RGB color String * @return {String} hexadecimal color String */ function RGBToHex(RGB) { var rgbArr = rgb.split(/[^\d]+/) var color = rgbArr[1]<<16 | rgbArr[2]<<8 | rgbArr[3] return '#'+ color.toString(16) } / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- hexToRGB (' # FFFFFF) / / 'RGB (255255255). RGBToHex (' RGB (255255255)) / / '# FFFFFF'Copy the code
Open the answer to the self-examination with notes
var num1 = 1 & 0; */ console.log(num1); */ console.log(num1); */ console.log(num1); //0 var num2 = 'string' & 1; /** * 'string' is a string (not a numeric type) that needs to be converted to a numeric value by Number() * Number('string') = NaN * Due to the side effects of NaN and Infinity on the bottom 64-bit conversion operation of the numeric value: Both values are treated as 0 * followed by 0 & 1 (0 when 0 is 0), so the final result is 0 */ console.log(num2); //0 var num3 = true & 1; /** * console.log(num3); /** * console.log(num3); /** console.log(num3); /** console.log(num3); //1 var num4 = undefined | false; /** * undefined is a non-numeric type, Number(undefined) = NaN (bit operator will treat NaN and Infinity as 0) * false is also a non-numeric type, Number(false) = 0 * NaN | 0 = 0 */ console.log(num4); //0 var num5 = undefined | true; /** * undefined is a non-numeric type, Number(undefined) = NaN (bit operator will treat NaN and Infinity as 0) * true is also a non-numeric type, Number (true) = 1 * NaN | 1 = 1 (or the characteristics of the operator to have 1, 1) * / console log (num5); //1 var num6 = 23 & 5; /** * 0001 0111 (23) * 0000 0101 (5) * 0000 0101 (answer: 5) */ console.log(num6); //5 var num7 = 23 | 5; /** * 0001 0111 (23) * 0000 0101 (5) * 0001 0111 (23) */ console.log(num7); //23 var num8 = 8 << 'string'; /** * 'string' is a string (not a numeric type),Number('string') = NaN * and NaN will be converted to 0 during the low-level conversion process, * so it is 8 << 0 = 8 */ console.log(num8); //8 var num9 = ({}) && 3; console.log(num9); //3 var num10 = ({}) & 3; console.log(num10); //0 var num11 = ({}) || 3; console.log(num11); //{} var num12 = ({}) | 3; console.log(num12); / / 3Copy the code