2. 按位异或的妙用

108 阅读4分钟

1:前言

按位异或(^)JavaScript 中的一种位运算符,这是一个我们既熟悉又陌生的的操作。 对于我个人,熟悉在我印象中最早接触是在大学计算机基础课程的时候老师有详细说过。 说陌生呢,在工作中却很少去使用这个东西(其实是不愿动脑,懒!)。 那今天就主要介绍一下主角按位异或,也算是一次复习。来不难,请随我一起看下去! 按位异或(^)是一个高效、简单、实用的操作符。

2:定义

按位异或(^)运算符在两个操作数中有且仅有一个对应的二进制位为1时,该位结果为1。

3:语法

a ^ b

4:运算真值表

aba XOR b
000
011
101
110
     9 (base 10) = 00000000000000000000000000001001 (base 2)
    14 (base 10) = 00000000000000000000000000001110 (base 2)
14 ^ 9 (base 10) = 00000000000000000000000000000111 (base 2) = 7 (base 10)

5:使用

5.1. 交换两个数

交互不加额外变量

let a = 5 // 二进制: 0101
let b = 3 // 二进制: 0011

a = a ^ b // a 变为 6 (0110)
b = a ^ b // b 变为 5 (0101)
a = a ^ b // a 变为 3 (0011)

console.log(a) // 输出: 3
console.log(b) // 输出: 5
5.1. 找出只出现一次的数字

在一个数组中,若所有数字都出现两次,只有一个数字出现一次,可以使用按位异或来找出这个数字。

const nums = [4, 1, 2, 1, 2]
let result = 0

for (const num of nums) {
result ^= num // 按位异或
}

console.log(result) // 输出: 4
// 如果不理解可以思考一下
5.3. 检查两个数字是否相等

如果两个数字相等,则它们的按位异或结果为 0。

const a = 5
const b = 5
const c = 3

console.log((a ^ b) === 0) // 输出: true
console.log((a ^ c) === 0) // 输出: false
5.4. 加密

异或运算可以用于加密

// 秘钥
var a = 123
// 明文
var b = 456
// 加密
var c = a ^ b
// 解密
var d = c ^ a

以下是一个实例,挺有意思的,可以运行一下试试

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>按位异或加密应用实例</title>
    <style>
      body {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
        font-family: Arial, sans-serif;
        background-color: #f4f4f4;
        margin: 0;
        padding: 20px;
      }
      .container {
        display: flex;
        flex-direction: column;
        align-items: center;
        background: white;
        border-radius: 8px;
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        padding: 20px;
        width: 300px;
      }
      .input-pwd-part {
        margin-top: 20px;
        display: flex;
        flex-direction: column;
        align-items: center;
      }
      textarea {
        width: 100%;
        padding: 10px;
        border: 1px solid #ccc;
        border-radius: 4px;
        resize: none;
        font-size: 14px;
      }
      input {
        width: 100%;
        padding: 10px;
        margin-top: 10px;
        border: 1px solid #ccc;
        border-radius: 4px;
        font-size: 14px;
      }
      button {
        width: 100%;
        padding: 10px;
        margin-top: 20px;
        background-color: #007bff;
        color: white;
        border: none;
        border-radius: 4px;
        font-size: 16px;
        cursor: pointer;
        transition: background-color 0.3s;
      }
      button:hover {
        background-color: #0056b3;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <textarea id="text" cols="30" rows="10" placeholder="请输入文本..."></textarea>
      <div class="input-pwd-part">
        <div>秘钥:</div>
        <input type="text" id="password" placeholder="请自定义加密秘钥..." />
      </div>
      <div>
        <button id="button">加密/解密</button>
      </div>
    </div>
    <script>
      function _doPuzzle(key, text) {
        let result = ''
        for (let i = 0; i < text.length; i++) {
          const keyIndex = i % key.length
          const keyCharCode = key.charCodeAt(keyIndex)
          const textCharCode = text.charCodeAt(i)
          const encryptedCharCode = textCharCode ^ keyCharCode
          result += String.fromCharCode(encryptedCharCode)
        }
        return result
      }
      document.getElementById('button').addEventListener('click', function () {
        const password = document.getElementById('password').value
        const text = document.getElementById('text').value
        if (password && text) {
          const result = _doPuzzle(password, text)
          document.getElementById('text').value = result
        } else {
          alert('请输入要加密的文本和秘钥')
        }
      })
    </script>
  </body>
</html>

5.5. 文件备份

异或运算可以用于数据备份

// 文件a
var a = 123
// 文件b
var b = 456
// 文件 a 和文件 b 进行异或运算,产生一个备份文件 c
var c = a ^ b
// 以后,无论是文件 a 或文件 b 损坏,只要不是两个原始文件同时损坏,就能根据另一个文件和备份文件,进行还原

6:总结

按位异或是一个非常强大的工具,在许多编程问题中提供了高效的解决方案。 无论是交换值、查找唯一元素、检查相等性、加密、备份,按位异或都能提供简洁且高效的实现方式。 话说这东西效率高,如果遇到高耗时运算也许可以试试

7:参考

www.ruanyifeng.com/blog/2021/0… developer.mozilla.org/en-US/docs/…