前端运算符详解:让你的代码更高效、更优雅

在前端开发过程中,JS 作为一种常用的脚本语言,承载着丰富的运算和操作功能。这些功能主要通过各种运算符来实现。本文将全面介绍 JS 中的各种运算符,并通过实例来加深理解。

本文将带你走进前端运算符的世界,从基础到高级,从常见到罕见,逐一解析它们的用法、特性和注意事项。我们将探讨算术运算符、比较运算符、逻辑运算符、位运算符、赋值运算符等各类运算符的工作原理,并通过实例展示如何在实际开发中运用它们。

掌握好各种运算符有利于代码的可读性

我们这边先来写几个实战,提高下兴趣,光看不会用也白搭。

实战

1.将一个值强制转换为布尔值

假如我们需要判断a是否存在,通常做法应该是 if(a){}, 这时我们对a的类型不确定,我们需要的做法是:

const a = null // 可能为 '' 可能为undefined
let flag = true

if(!!a) {
    // do someing
    
    flag = !!a
}

连续使用两个 ! 运算符 !! 的目的通常是将一个值强制转换为布尔值。这是因为 ! 运算符会将其操作数转换为一个布尔值,然后再次取反。通过这种方式,任何非布尔值都可以被转换为一个明确的 true 或 false

!! 在开发中常被用作一种快捷的方式来进行显式的布尔类型转换。

2.将数字转换为整数

更常见和更明确的方法是使用 Math.floor()Math.ceil()Math.round(), 或简单的类型转换(如 Number(value) 或 value | 0)来得到整数。

console.log(~~4.9); // 输出: 4
console.log(~~-4.9); // 输出: -4

~~ 的行为类似于将数字转换为整数。它首先对其操作数执行按位非操作(~),然后再执行一次按位非操作。由于按位非操作是对数字的二进制表示进行操作的,因此这种双重操作最终会去掉数字的小数部分,从而得到一个整数。

它可以被用作一种技巧来将数字转换为整数。

3.优化存储空间

假设你正在处理大量的布尔值数据,并且想要有效地存储这些数据。由于布尔值只有两种状态(真或假),你可以使用单个位来存储每个布尔值,而不是使用完整的字节或更大的数据类型。

function storeBooleans(bools) {  
  let bits = 0;  
  let position = 0;  
  for (let i = 0; i < bools.length; i++) {  
    if (bools[i]) {  
      bits |= (1 << position); // 设置对应位为1  
    }  
    position++;  
    if (position >= 32) { // 32位是一个整数的最大位数  
      // 处理当前的整数,并重置位置和bits  
      // ...  
      position = 0;  
      bits = 0;  
    }  
  }  
  // 返回存储布尔值的整数数组或其他数据结构  
  return [bits]; // 这里只返回了一个整数作为示例  
}  
  
const booleans = [true, false, true, true, false];  
const stored = storeBooleans(booleans);  
console.log(stored); // 输出存储布尔值的整数数组

4.实现简单的哈希函数

位运算可以用于创建简单的哈希函数,该函数可以将一个字符串或数字映射到一个较小的整数范围。

function simpleHash(str) {  
  let hash = 0;  
  for (let i = 0; i < str.length; i++) {  
    hash = (hash << 5) - hash + str.charCodeAt(i); // 左移、减去自身并加上字符的ASCII码  
    hash |= 0; // 确保hash是一个32位整数  
  }  
  return hash;  
}  
  
const str = "hello";  
const hashed = simpleHash(str);  
console.log(hashed); // 输出哈希值

5.图像处理中的颜色操作

在处理图像数据时,位运算可以用来快速地修改像素的颜色值。

function invertColor(color) {  
  // 假设color是一个由RGB组成的整数,其中红色、绿色和蓝色分别占据8位  
  const inverted = ~color & 0xFFFFFF; // 取反并保留低24位(RGB值)  
  return inverted;  
}  
  
const originalColor = 0xFF0000; // 红色  
const invertedColor = invertColor(originalColor);  
console.log(invertedColor.toString(16)); // 输出反转后的颜色值

6.检测一个数是否为2的幂

使用位运算可以高效地检测一个数是否是2的幂。

function isPowerOfTwo(n) {  
  return (n > 0) && ((n & (n - 1)) === 0);  
}  
  
console.log(isPowerOfTwo(4)); // 输出: true  
console.log(isPowerOfTwo(6)); // 输出: false

7.交换两个变量的值

不使用临时变量,只使用位运算交换两个变量的值。

let a = 5;  
let b = 10;  
  
a = a ^ b;  
b = a ^ b;  
a = a ^ b;  
  
console.log(a); // 输出: 10  
console.log(b); // 输出: 5

8.切换位状态

假设你有一个整数,并且你想要切换(取反)它的某一位。你可以使用按位异或(^)运算符来实现这一点。

let num = 5; // 二进制: 0101  
let bitToFlip = 2; // 我们想要切换第2位(从右边数起,从0开始)  
let mask = 1 << bitToFlip; // 创建一个掩码,第2位为1,其余为0  
num = num ^ mask; // 切换num的第2位  
console.log(num); // 输出: 7 (二进制: 0111)

9.检查某一位是否为1

你可以通过与运算(&)和一个掩码来检查一个整数的某一位是否为1。

let num = 10; // 二进制: 1010  
let bitToCheck = 1; // 我们想要检查第1位(从右边数起,从0开始)  
let mask = 1 << bitToCheck; // 创建一个掩码,第1位为1,其余为0  
let isBitSet = (num & mask) !== 0; // 如果结果为非0,则该位被设置  
console.log(isBitSet); // 输出: true

10.设置某一位为1

你可以使用或运算(|)来确保一个整数的某一位被设置为1。

let num = 3; // 二进制: 0011  
let bitToSet = 2; // 我们想要设置第2位(从右边数起,从0开始)为1  
let mask = 1 << bitToSet; // 创建一个掩码,第2位为1,其余为0  
num = num | mask; // 设置num的第2位为1  
console.log(num); // 输出: 7 (二进制: 0111)

11. 清除某一位

你可以使用按位与(&)和取反(~)运算符来清除一个整数的某一位。

let num = 7; // 二进制: 0111  
let bitToClear = 1; // 我们想要清除第1位(从右边数起,从0开始)  
let mask = ~(1 << bitToClear); // 创建一个掩码,第1位为0,其余为1  
num = num & mask; // 清除num的第1位  
console.log(num); // 输出: 6 (二进制: 0110)

12.位运算实现整数乘法

位运算也可以用来实现整数的乘法,尽管这在现代JavaScript引擎中可能不如内置的乘法运算符高效,但在某些特定场景下可能有用。

function multiply(a, b) {  
  let result = 0;  
  while (b > 0) {  
    if (b & 1) { // 检查b的最低位是否为1  
      result = result + a; // 如果是,则将a加到结果中  
    }  
    a <<= 1; // 将a左移一位(相当于乘以2b >>= 1; // 将b右移一位  
  }  
  return result;  
}  
  
console.log(multiply(5, 3)); // 输出: 15

这里基本以比较生僻的位运算为例子,基本运算比如三元、加减乘除等运算符,想必大家用的也不比我少

然而在实际开发中,位运算符的复杂运算通常用于性能优化、低级编码、图形处理、加密算法等场景。

运算符概念例子大全

算术运算符

算术运算符主要用于执行数值的加、减、乘、除等基本运算。

  • 加法 (+):用于两个数值的相加,也可以用于字符串连接。
  • 减法 (-):用于两个数值的相减。
  • 乘法 (*):用于两个数值的相乘。
  • 除法 (/):用于两个数值的相除。
  • 取模 (%):返回两数相除的余数。
  • 递增 (++):将变量的值加1。
  • 递减 (--):将变量的值减1。
let a = 5;  
let b = 3;  
  
let sum = a + b;       // 加法:8  
let difference = a - b; // 减法:2  
let product = a * b;    // 乘法:15  
let quotient = a / b;   // 除法:1.6666666666666667  
let remainder = a % b;  // 取模:2
a++;        // 执行后加1
--b;        // 执行前先减1

比较运算符

比较运算符用于比较两个值的大小或是否相等。

  • 等于 (==):检查两个值是否相等,会进行类型转换。
  • 严格等于 (===):检查两个值是否严格相等,不会进行类型转换。
  • 不等于 (!=):检查两个值是否不相等,会进行类型转换。
  • 严格不等于 (!==):检查两个值是否严格不相等,不会进行类型转换。
  • 大于 (>):检查左边的值是否大于右边的值。
  • 小于 (<):检查左边的值是否小于右边的值。
  • 大于等于 (>=):检查左边的值是否大于或等于右边的值。
  • 小于等于 (<=):检查左边的值是否小于或等于右边的值。
let x = 10;  
let y = 20;  
  
let isEqual = x == y;    // 相等:false  
let isNotEqual = x != y; // 不相等:true  
let isStrictEqual = x === y; // 严格相等:false  
let isStrictNotEqual = x !== y; // 严格不相等:true  
let isGreaterThan = x > y; // 大于:false  
let isLessThan = x < y;   // 小于:true
let isEqualLessThan = x <= y; // 小于等于 true
let isEqualGreaterThan= x >= y; // 大于等于:true

逻辑运算符

逻辑运算符用于组合或否定布尔值。

  • 逻辑与 (&&):当两个操作数都为真时返回真。
  • 逻辑或 (||):当两个操作数中至少有一个为真时返回真。
  • 逻辑非 (!):返回操作数的反值。
let isTrue = true;  
let isFalse = false;  
  
let andResult = isTrue && isFalse;  // 逻辑与:false  
let orResult = isTrue || isFalse;   // 逻辑或:true  
let notResult = !isTrue;             // 逻辑非:false

赋值运算符

赋值运算符用于给变量赋值。

  • 赋值 (=):将右侧的值赋给左侧的变量。
  • 加法赋值 (+=):将右侧的值加到左侧的变量上,并将结果赋值给左侧的变量。
  • 减法赋值 (-=):从左侧的变量中减去右侧的值,并将结果赋值给左侧的变量。
  • 乘法赋值 (*=):将左侧的变量乘以右侧的值,并将结果赋值给左侧的变量。
  • 除法赋值 (/=):将左侧的变量除以右侧的值,并将结果赋值给左侧的变量。
let num = 5;  
num += 3; // 相当于 num = num + 3; 结果:num 为 8  
num -= 2; // 相当于 num = num - 2; 结果:num 为 6  
num *= 4; // 相当于 num = num * 4; 结果:num 为 24  
num /= 2; // 相当于 num = num / 2; 结果:num 为 12

三元运算符

条件运算符是一个特殊的运算符,它接受三个操作数,并根据条件返回两个值之一。

let age = 15;  
let beverage = (age >= 21) ? "Beer" : "Juice"; // 根据年龄返回不同的饮料  
console.log(beverage); // 输出 "Juice"

类型运算符

类型运算符用于确定变量的类型。

let str = "Hello";  
let num = 42;  
  
let strType = typeof str; // 字符串类型:"string"  
let numType = typeof num; // 数字类型:"number"

位运算符

位运算符直接对二进制位进行操作,通常在处理低级编程或优化性能时使用。

  • 按位与(&):对两个数的每一位执行与操作。只有当两个相应的二进制位都为1时,结果的该位才为1。
  • 按位或(|):对两个数的每一位执行或操作。只要两个相应的二进制位中有一个为1,结果的该位就为1。
  • 按位异或(^):对两个数的每一位执行异或操作。当两个相应的二进制位不同时,结果的该位为1;相同时,结果的该位为0。
  • 按位非(~):对一个数的每一位执行非操作。二进制位的0变为1,1变为0。
  • 左移(<<):将一个数的所有位向左移动指定的位数,右侧用0填充。
  • 右移(>>):将一个数的所有位向右移动指定的位数,左侧用该数的符号位填充(正数用0填充,负数用1填充)。
  • 无符号右移(>>>):将一个数的所有位向右移动指定的位数,左侧总是用0填充。这常用于处理无符号整数。
let a = 60;  // 60 = 0011 1100  
let b = 13;  // 13 = 0000 1101  
  
let andResult = a & b;  // 12 = 0000 1100  
let orResult = a | b;   // 61 = 0011 1101  
let xorResult = a ^ b;  // 49 = 0011 0001  
let notResult = ~a;    // -61 = 1100 0011 (二进制补码形式)
let leftShift = a << 2; // 240 = 1111 0000
let rightShift a >> 2; // 15 = 0000 1111
let unsignedResult = b >>> 1; // 6 = 1101 0110

其他运算符

JS 还包含一些其他运算符,如 in 运算符用于检查对象是否含有某个属性,instanceof 运算符用于检测构造函数的 prototype 属性是否出现在对象的原型链中,delete 运算符用于删除对象的属性等。

let obj = {  
    name: "Alice",  
    age: 30  
};  
  
console.log("name" in obj); // 输出 true  
console.log(obj instanceof Object); // 输出 true  
  
delete obj.age;  
console.log(obj.age); // 输出 undefined

总结

在复杂运算中,这些运算符可以组合使用,以实现各种复杂的逻辑和功能。同时,由于位运算直接对二进制位进行操作,因此通常比普通的算术运算更快更适合处理大量数据或需要高效运算的场景。

原文链接:https://juejin.cn/post/7353226130822742070 作者:大码猴

(0)
上一篇 2024年4月3日 上午11:13
下一篇 2024年4月3日 下午4:06

相关推荐

发表回复

登录后才能评论