JavaScript入门必学5:这些符号你真的懂吗?位运算符、一元运算符等冷门知识
# JavaScript入门必学5:这些符号你真的懂吗?位运算符、一元运算符等冷门知识
## 开篇:编程里的「隐藏技能」,关键时刻能救场
想象你学完基础运算符后,能熟练做计算、判断和赋值,但总感觉自己像刚学会用菜刀切菜的厨师——能完成基本操作,却没见识过更高级的厨具(比如雕刻刀、压面机)。今天我们要聊的**位运算符**和**一元运算符**,就是JavaScript里的「高级厨具」。它们虽然不常用,但在特定场景下能大幅提升效率,甚至解决一些棘手问题。
---
## 一、位运算符:和二进制「打交道」的魔法
位运算符的名字听起来很「硬核」,但本质上是一组直接操作数值**二进制位**(0和1)的工具。计算机底层所有数据最终都会转成二进制,因此位运算相当于直接和计算机的「母语」对话。
### 1. 为什么需要位运算?
举个生活例子:你想设计一个「权限系统」,用户可能有「读」「写」「删除」三种权限。用普通变量存储可能需要多个布尔值(如 `canRead: true`、`canWrite: false`),但如果用二进制位,一个数字就能搞定:
- 读权限:`001`(二进制)→ 十进制1
- 写权限:`010`(二进制)→ 十进制2
- 删除权限:`100`(二进制)→ 十进制4
用户有「读+写」权限就是 `001 | 010 = 011`(二进制)→ 十进制3。这种用二进制位组合信息的方式,就是位运算的典型应用。
### 2. 常见的位运算符(附生活类比)
JavaScript提供了7种位运算符,我们用「灯的开关」(0=关,1=开)来类比理解:
| 运算符 | 名称 | 作用(对两个数的每一位操作) | 生活类比 | 示例(十进制转二进制) |
|--------|------------|------------------------------|------------------------------|------------------------------|
| `&` | 按位与 | 两位都为1时结果为1,否则为0 | 两个开关都打开,灯才亮 | `3 & 5` → `011 & 101 = 001` → 1 |
| `|` | 按位或 | 至少一位为1时结果为1 | 至少一个开关打开,灯就亮 | `3 | 5` → `011 | 101 = 111` → 7 |
| `^` | 按位异或 | 两位不同时结果为1,相同时为0 | 两个开关状态不同,灯才亮 | `3 ^ 5` → `011 ^ 101 = 110` → 6 |
| `~` | 按位非 | 单目运算符,将每一位取反(0变1,1变0) | 把灯的状态完全反转(开→关,关→开) | `~3` → `~00000011 = 11111100` → -4(补码表示) |
| `<<` | 左移 | 将二进制位向左移动n位,右侧补0 | 把灯的数量翻倍(左移1位=×2) | `3 <>` | 右移(带符号) | 将二进制位向右移动n位,左侧补符号位(正数补0,负数补1) | 把灯的数量减半(右移1位=÷2取整) | `6 >> 1` → `0110 → 0011` → 3(6÷2=3) |
| `>>>` | 无符号右移 | 向右移动n位,左侧补0(无论正负) | 强制把数当正数处理后减半 | `-6 >>> 1` → `11111010 → 01111010` → 122(特殊场景用) |
### 3. 实际应用场景
#### 场景1:快速计算倍数
左移 `<>` 相当于除以2的n次方(取整)。这在处理二进制数据或性能敏感的场景(如图形计算)中非常高效:
```javascript
let num = 5;
console.log(num <> 1); // 5÷2=2(二进制101→10)
```
#### 场景2:权限系统设计
用位掩码组合权限,节省存储空间:
```javascript
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:
```javascript
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++` | 先使用旧值,再自增1 | `console.log(count++)` → 0(count变为1) |
| `--count` | 先自减1,再使用新值 | `console.log(--count)` → -1(count变为-1) |
| `count--` | 先使用旧值,再自减1 | `console.log(count--)` → 0(count变为-1) |
**关键记忆点**:
- 前置(`++count`):先操作,后使用 → 结果是新值
- 后置(`count++`):先使用,后操作 → 结果是旧值
**实际应用**:
```javascript
// 循环中使用后置++:先判断条件,再自增
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()`)
```javascript
console.log(+ "123"); // 123(字符串转数字)
console.log(+ true); // 1(布尔值true转1)
console.log(+ null); // 0(null转0)
console.log(+ "abc"); // NaN(无法转换的字符串转NaN)
```
- **快速取反**:`-` 可以将数字取反,或对非数字类型先转数字再取反
```javascript
console.log(-5); // -5
console.log(- "10"); // -10(字符串转数字后取反)
console.log(- true); // -1(布尔值转数字后取反)
```
### 3. `typeof`:查看变量的「类型身份证」(再复习)
`typeof` 可以返回变量的类型字符串,但需要注意 `null` 的特殊情况:
```javascript
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` 运算符用于删除对象的**自身属性**(无法删除继承的属性):
```javascript
let user = {
name: "小明",
age: 18
};
console.log(user.name); // "小明"(存在name属性)
delete user.name; // 删除name属性
console.log(user.name); // undefined(name属性被删除)
```
**注意事项**:
- 无法删除用 `var`/`let`/`const` 声明的全局变量(它们属于全局对象的不可配置属性)
- 删除数组元素会留下「空洞」,但数组长度不变:
```javascript
let arr = [1, 2, 3];
delete arr[1];
console.log(arr); // [1, empty, 3]
console.log(arr.length); // 3(长度不变)
```
### 5. `void`:执行表达式但「不返回值」
`void` 运算符会执行后面的表达式,但**始终返回 `undefined`**。常见于两种场景:
- **阻止默认行为**(早期JavaScript中):
```html
点击我
```
- **立即执行函数表达式(IIFE)**:
```javascript
void function() {
console.log("这个函数执行了,但返回值被忽略");
}();
```
---
## 三、逗号运算符:一行代码的「多任务处理」
逗号运算符 `,` 可以在一行中执行多个表达式,**返回最后一个表达式的结果**(前面的表达式会被执行,但结果被忽略)。它在需要简化代码或循环中同时操作多个变量时很有用。
### 1. 基础用法:执行多个操作
```javascript
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` 循环中,逗号运算符可以同时初始化或更新多个变量:
```javascript
// 同时遍历数组的索引和值(旧写法)
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位有符号整数**(超出部分会被截断):
```javascript
let bigNum = 0x123456789; // 十进制8198552921(超过32位)
console.log(bigNum <0)
return n > 0 && (n & (n - 1)) === 0;
}
console.log(isPowerOfTwo(8)); // 应该输出true(8是2³)
console.log(isPowerOfTwo(6)); // 应该输出false(6不是2的幂)
```
2. **进阶题**:用 `delete` 删除对象属性,并验证是否删除成功
```javascript
let car = {
brand: "特斯拉",
price: 1000000
};
delete car.price;
console.log(car.price); // 输出:undefined(price属性被删除)
```
3. **陷阱题**:预测下面代码的输出结果
```javascript
let x = 5;
let y = (x = 10, x + 5); // 先执行x=10(x变为10),再计算10+5=15
console.log(x, y); // 输出:10 15
```
---
## 总结:冷门运算符的核心价值
| 技能点 | 掌握程度检查 |
|-----------------|----------------------------------|
| 位运算符 | 知道 `&`、`|`、`<<` 等的作用,了解权限系统等应用场景 |
| 一元运算符 | 理解 `++`/`--` 的前置后置区别,会用 `typeof` 和 `delete` |
| 逗号运算符 | 知道其返回最后一个表达式的特性,能在循环中简化代码 |
**最后提醒**:这些运算符虽然「冷门」,但面试中可能被问到(比如判断奇偶、权限设计)。建议先掌握基础运算符,再回头学习这些进阶内容。遇到具体问题(比如「如何用位运算优化代码」)时,再深入研究会更高效。
如果对某个运算符想深入了解,欢迎随时提问!比如:"位运算符在Node.js中处理Buffer时怎么用?" 或 "delete和delete操作符有什么区别?"
3 分钟阅读
413 字
如果文章对您有帮助,欢迎支持作者继续创作