二进制与前端

242 阅读6分钟

二进制在react源码中的应用

点击 这里 查看源码

...
// DOM需要插入到页面中
export const Placement = /*                */ 0b00000000000010;
// DOM需要更新
export const Update = /*                   */ 0b00000000000100;
// DOM需要插入到页面中并更新
export const PlacementAndUpdate = /*       */ 0b00000000000110;
// DOM需要删除
export const Deletion = /*                 */ 0b00000000001000;
...

以上是关于react源码中的节选,但我并不想展开讲源码的内容,只是想让大家知道二进制在实际开发中的使用。

js中的二进制

// js中的二进制是以0b开头的,如下所示:

// 正数
console.log(0b00000000000010); // 2
console.log(0b00000000000100); // 4

// 负数
console.log(-0b00000000000010); // -2
console.log(-0b00000000000100); // -4

原码、反码、补码

  • 原码:二进制表示法,最高位表示符号位,0表示正数,1表示负数
  • 反码:正数的反码与原码相同,负数的反码是对原码逐位取反,符号位保持不变
  • 补码:正数的补码与原码相同,负数的补码是对原码逐位取反,然后在最后一位加1

下面是几个例子:

/*
例:求5的二进制原码、反码、补码(三个都相同)
  5的二进制原码:00000000000000000000000000000101
  5的反码:00000000000000000000000000000101
  5的补码(反码+1):00000000000000000000000000000101


  例:求-5的二进制原码、反码、补码
  -5的二进制原码:-101
  -5的反码:11111111111111111111111111111010
  -5的补码(反码+1):11111111111111111111111111111011
*/

位运算符

位运算符主要分为两大类

1、位移运算符:

  • <<:左移,将一个数的二进制码整体左移若干位,高位丢弃,低位补0
  • >>:右移,将一个数的二进制码整体右移若干位,对正数,高位补0,对负数,高位补1
  • >>>:无符号右移,将一个数的二进制码整体右移若干位,高位补0

注意:位移运算符是对数的补码进行位移

下面是几个列子:

/*
例:
  正数:
  5的补码为00000000000000000000000000000101

  5 << 2:00000000000000000000000000010100,结果为20
  5 >> 2:00000000000000000000000000000001,结果为1

  负数:
  这里的-5要先求出补码,-5的补码为11111111111111111111111111111011
  -5 << 2:11111111111111111111111111101100,结果为-20
  -5 >> 2:11111111111111111111111111111110,结果为-2
  -5 >>> 2:00111111111111111111111111111110,结果为1073741822

  说明:
  -5 << 2   =>  11111111111111111111111111101100
  这里算出的是补码,所以要转换成原码
  已知负数的补码是对其反码+1,所以其反码为
  11111111111111111111111111101100 - 1 = 11111111111111111111111111101011
  所以其原码为
  10000000000000000000000000010100 => -20
*/

2、位逻辑运算符

  • &:按位与,两个数的二进制码对应位都为1,结果为1,否则为0
  • |:按位或,两个数的二进制码对应位都为0,结果为0,否则为1
  • ^:按位异或,两个数的二进制码对应位相同,结果为0,否则为1
  • ~:按位非,对一个数的二进制码按位取反,即0变1,1变0

下面是几个列子:


const C = 0b101;
const D = 0b110;

//   C & D  => 0b100
//   C | D  => 0b111
//   C ^ D  => 0b011

/*
例:
  ~5
  5的补码为00000000000000000000000000000101
  ~5 => 11111111111111111111111111111010
  5的反码为11111111111111111111111111111001
  5的原码为10000000000000000000000000000110
  所以~5的结果为-6

  ~-5
  -5的补码为11111111111111111111111111111011
  ~-5 => 00000000000000000000000000000100
  -5的反码为11111111111111111111111111111011
  -5的原码为10000000000000000000000000000100
  所以~5的结果为4
*/

注意:~是对数的补码进行取反

二进制在权限控制中的应用

回归主题,我们声明几个变量,分别表示权限:

const read = 0b100; // 读的权限
const write = 0b010; // 写的权限
const execute = 0b001; // 执行的权限


// 添加权限
// 我们我们想给某个用户添加读写和执行权限,那么我们可以这样做
const readAndWrite = read | write | execute; // 0b111

// 检查权限
// 我们想检查某个用户是否有某种权限,那么我们可以这样做
const hasRead = (readAndWrite & read) === read; // true
const hasWrite = (readAndWrite & write) === write; // true

// 删除权限
// 我们想删除某个用户的某种权限,那么我们可以这样做:给想要删除的权限取反,然后与原权限进行按位与运算
const noRead = readAndWrite & ~read; // 0b011
const noWrite = readAndWrite & ~write; // 0b101
const noExecute = readAndWrite & ~execute; // 0b110

拓展,小数的二进制表示

/*
  例如:0.6
  方法:乘2取整,直到小数为0
  0.6 * 2 = 1.2 => 1
  0.2 * 2 = 0.4 => 0
  0.4 * 2 = 0.8 => 0
  0.8 * 2 = 1.6 => 1
  0.6 * 2 = 1.2 => 1
  0.2 * 2 = 0.4 => 0
  0.4 * 2 = 0.8 => 0
  0.8 * 2 = 1.6 => 1
  ...

  此时,0.6是一个无限循环小数,二进制码为:0b0.1001100110011001100110011001100110011001100110011001...

  Q:为什么 0.1 + 0.2 = 0.30000000000000004
  0.1的二进制码:0b0.0001100110011001100110011001100110011001100110011001...
  0.2的二进制码:0b0.0011001100110011001100110011001100110011001100110011...
  0.1 + 0.2的二进制码:0b0.0100110011001100110011001100110011001100110011001100...
  0.1 + 0.2的十进制码:0.30000000000000004
*/