JavaScript入门必学5:这些符号你真的懂吗?位运算符、一元运算符等冷门知识

JavaScript入门必学5:这些符号你真的懂吗?位运算符、一元运算符等冷门知识

开篇:编程里的「隐藏技能」,关键时刻能救场

想象你学完基础运算符后,能熟练做计算、判断和赋值,但总感觉自己像刚学会用菜刀切菜的厨师——能完成基本操作,却没见识过更高级的厨具(比如雕刻刀、压面机)。今天我们要聊的位运算符一元运算符,就是JavaScript里的「高级厨具」。它们虽然不常用,但在特定场景下能大幅提升效率,甚至解决一些棘手问题。


一、位运算符:和二进制「打交道」的魔法

位运算符的名字听起来很「硬核」,但本质上是一组直接操作数值二进制位(0和1)的工具。计算机底层所有数据最终都会转成二进制,因此位运算相当于直接和计算机的「母语」对话。

1. 为什么需要位运算?

举个生活例子:你想设计一个「权限系统」,用户可能有「读」「写」「删除」三种权限。用普通变量存储可能需要多个布尔值(如 canRead: truecanWrite: false),但如果用二进制位,一个数字就能搞定:

  • 读权限:001(二进制)→ 十进制1
  • 写权限:010(二进制)→ 十进制2
  • 删除权限:100(二进制)→ 十进制4

用户有「读+写」权限就是 001 | 010 = 011(二进制)→ 十进制3。这种用二进制位组合信息的方式,就是位运算的典型应用。

2. 常见的位运算符(附生活类比)

JavaScript提供了7种位运算符,我们用「灯的开关」(0=关,1=开)来类比理解:

运算符名称作用(对两个数的每一位操作)生活类比示例(十进制转二进制)
&按位与两位都为1时结果为1,否则为0两个开关都打开,灯才亮3 & 5011 & 101 = 001 → 1
``按位或至少一位为1时结果为1至少一个开关打开,灯就亮
^按位异或两位不同时结果为1,相同时为0两个开关状态不同,灯才亮3 ^ 5011 ^ 101 = 110 → 6
~按位非单目运算符,将每一位取反(0变1,1变0)把灯的状态完全反转(开→关,关→开)~3~00000011 = 11111100 → -4(补码表示)
<<左移将二进制位向左移动n位,右侧补0把灯的数量翻倍(左移1位=×2)3 << 10011 → 0110 → 6(3×2=6)
>>右移(带符号)将二进制位向右移动n位,左侧补符号位(正数补0,负数补1)把灯的数量减半(右移1位=÷2取整)6 >> 10110 → 0011 → 3(6÷2=3)
>>>无符号右移向右移动n位,左侧补0(无论正负)强制把数当正数处理后减半-6 >>> 111111010 → 01111010 → 122(特殊场景用)

3. 实际应用场景

场景1:快速计算倍数

左移 << 相当于乘以2的n次方,右移 >> 相当于除以2的n次方(取整)。这在处理二进制数据或性能敏感的场景(如图形计算)中非常高效:

let num = 5;
console.log(num << 2);  // 5×2²=20(二进制101→10100)
console.log(num >> 1);  // 5÷2=2(二进制101→10)

场景2:权限系统设计

用位掩码组合权限,节省存储空间:

const READ = 1;    // 001
const WRITE = 2;   // 010
const DELETE = 4;  // 100

let userPermissions = READ | WRITE;  // 001 | 010 = 011 → 3(有读+写权限)

// 检查是否有写权限:用按位与判断对应位是否为1
console.log((userPermissions & WRITE) !== 0);  // true(有写权限)

场景3:判断奇偶性(比取模更快)

一个数是偶数当且仅当二进制最后一位是0,奇数则是1:

let num = 7;
console.log((num & 1) === 0);  // false(最后一位是1,奇数)
console.log((num & 1) === 1);  // true

二、一元运算符:只操作一个数的「快捷按钮」

一元运算符只需要一个操作数,比如 +5-3++count 等。它们看似简单,但有些用法可能让你「大跌眼镜」。

1. 自增/自减:++-- 的「前置后置」陷阱

我们之前学过 ++(自增)和 --(自减),但它们的「前置」和「后置」写法会导致不同结果,需要重点复习:

写法含义示例(初始count=0)
++count先自增1,再使用新值console.log(++count) → 1(count变为1)
count++先使用旧值,再自增1console.log(count++) → 0(count变为1)
--count先自减1,再使用新值console.log(--count) → -1(count变为-1)
count--先使用旧值,再自减1console.log(count--) → 0(count变为-1)

关键记忆点

  • 前置(++count):先操作,后使用 → 结果是新值
  • 后置(count++):先使用,后操作 → 结果是旧值

实际应用

// 循环中使用后置++:先判断条件,再自增
for (let i = 0; i < 3; i++) {
  console.log(i);  // 输出0, 1, 2(i先参与循环体,再自增)
}

// 前置++的特殊用法:快速跳过某个值
let j = 0;
console.log(++j);  // 直接输出1(j变为1)

2. 正负号:+- 的「隐藏功能」

你可能知道 +5 就是5,-3 就是-3,但它们还有两个隐藏用法:

  • 显式转换数字类型+ 可以将字符串或其他类型转为数字(类似 Number()

    console.log(+ "123");    // 123(字符串转数字)
    console.log(+ true);     // 1(布尔值true转1)
    console.log(+ null);     // 0(null转0)
    console.log(+ "abc");    // NaN(无法转换的字符串转NaN)
  • 快速取反- 可以将数字取反,或对非数字类型先转数字再取反

    console.log(-5);         // -5
    console.log(- "10");     // -10(字符串转数字后取反)
    console.log(- true);     // -1(布尔值转数字后取反)

3. typeof:查看变量的「类型身份证」(再复习)

typeof 可以返回变量的类型字符串,但需要注意 null 的特殊情况:

console.log(typeof 42);          // "number"
console.log(typeof "hello");     // "string"
console.log(typeof true);        // "boolean"
console.log(typeof undefined);   // "undefined"
console.log(typeof null);        // "object"(历史bug,需用===null判断)
console.log(typeof { name: "小明" });  // "object"
console.log(typeof function(){});      // "function"(函数是特殊的对象)

4. delete:删除对象的「私有财产」

delete 运算符用于删除对象的自身属性(无法删除继承的属性):

let user = {
  name: "小明",
  age: 18
};

console.log(user.name);  // "小明"(存在name属性)
delete user.name;        // 删除name属性
console.log(user.name);  // undefined(name属性被删除)

注意事项

  • 无法删除用 var/let/const 声明的全局变量(它们属于全局对象的不可配置属性)
  • 删除数组元素会留下「空洞」,但数组长度不变:
    let arr = [1, 2, 3];
    delete arr[1];
    console.log(arr);        // [1, empty, 3]
    console.log(arr.length); // 3(长度不变)

5. void:执行表达式但「不返回值」

void 运算符会执行后面的表达式,但始终返回 undefined。常见于两种场景:

  • 阻止默认行为(早期JavaScript中):

    <a href="https://example.com" onclick="void alert('点击了链接')">点击我</a>
    <!-- 点击后弹出提示,但不会跳转页面 -->
  • 立即执行函数表达式(IIFE)

    void function() {
      console.log("这个函数执行了,但返回值被忽略");
    }();

三、逗号运算符:一行代码的「多任务处理」

逗号运算符 , 可以在一行中执行多个表达式,返回最后一个表达式的结果(前面的表达式会被执行,但结果被忽略)。它在需要简化代码或循环中同时操作多个变量时很有用。

1. 基础用法:执行多个操作

let a = 1;
let b = 2;
let c = (a++, b++, a + b);  // 先执行a++(a=2),再执行b++(b=3),最后计算a+b=5
console.log(c);  // 输出:5

2. 循环中的「隐藏技能」

for 循环中,逗号运算符可以同时初始化或更新多个变量:

// 同时遍历数组的索引和值(旧写法)
let arr = ["a", "b", "c"];
for (let i = 0, j = arr.length - 1; i <= j; i++, j--) {
  console.log(`索引${i}和${j}的值:${arr[i]}, ${arr[j]}`);
}
// 输出:
// 索引0和2的值:a, c
// 索引1和1的值:b, b

四、常见陷阱:这些坑别踩!

1. 位运算符的「32位限制」

JavaScript中的位运算会将操作数转换为32位有符号整数(超出部分会被截断):

let bigNum = 0x123456789;  // 十进制8198552921(超过32位)
console.log(bigNum << 1);  // 结果为-1431655766(截断为32位后计算)

2. delete 无法删除继承属性

let obj = Object.create({ x: 10 });  // obj继承自{x:10}
delete obj.x;                        // 无法删除继承的x属性
console.log(obj.x);  // 10(仍然存在)

3. 逗号运算符的「优先级最低」

逗号运算符的优先级比大多数运算符低,使用时需加括号避免错误:

let x = (1 + 2, 3 + 4);  // 正确:先算1+2=3,再算3+4=7 → x=7
let y = 1 + 2, 3 + 4;    // 错误:等价于 (let y=1+2), (3+4) → 语法错误

五、练习时间:动手试试冷门运算符

  1. 基础题:用位运算符判断一个数是否是2的幂(2的幂的二进制只有最高位是1,如2→10,4→100)

    function isPowerOfTwo(n) {
      // 你的代码:n & (n-1) 会消去最后一位1,若结果为0则是2的幂(n>0)
      return n > 0 && (n & (n - 1)) === 0;
    }
    console.log(isPowerOfTwo(8));  // 应该输出true(8是2³)
    console.log(isPowerOfTwo(6));  // 应该输出false(6不是2的幂)
  2. 进阶题:用 delete 删除对象属性,并验证是否删除成功

    let car = {
      brand: "特斯拉",
      price: 1000000
    };
    delete car.price;
    console.log(car.price);  // 输出:undefined(price属性被删除)
  3. 陷阱题:预测下面代码的输出结果

    let x = 5;
    let y = (x = 10, x + 5);  // 先执行x=10(x变为10),再计算10+5=15
    console.log(x, y);  // 输出:10 15

总结:冷门运算符的核心价值

技能点掌握程度检查
位运算符知道 &、`
一元运算符理解 ++/-- 的前置后置区别,会用 typeofdelete
逗号运算符知道其返回最后一个表达式的特性,能在循环中简化代码

最后提醒:这些运算符虽然「冷门」,但面试中可能被问到(比如判断奇偶、权限设计)。建议先掌握基础运算符,再回头学习这些进阶内容。遇到具体问题(比如「如何用位运算优化代码」)时,再深入研究会更高效。

如果对某个运算符想深入了解,欢迎随时提问!比如:“位运算符在Node.js中处理Buffer时怎么用?” 或 “delete和delete操作符有什么区别?”

💬 评论

加载中...