Skip to content

运算符

运算符用于执行各种操作,如算术运算、比较、逻辑判断等。本章将详细介绍 JavaScript 中的各类运算符。

算术运算符

算术运算符用于执行数学计算。

基本算术运算符

javascript
// 加法运算符 (+)
let sum = 10 + 5;        // 15
let concat = 'Hello ' + 'World';  // 'Hello World'(字符串拼接)
let numStr = 10 + '5';   // '105'(数字与字符串拼接)

// 减法运算符 (-)
let diff = 10 - 5;       // 5
let negNum = 10 - '5';   // 5(字符串转换为数字)

// 乘法运算符 (*)
let product = 10 * 5;    // 50
let repeat = 'ab' * 3;   // NaN(字符串不能相乘)

// 除法运算符 (/)
let quotient = 10 / 5;   // 2
let division = 10 / 3;   // 3.333...
let divByZero = 10 / 0;  // Infinity

// 取余运算符 (%)
let remainder = 10 % 3;  // 1(10 除以 3 余 1)
let negRemainder = -10 % 3;  // -1(结果符号与被除数相同)
let posRemainder = 10 % -3;  // 1

// 幂运算符 (**) - ES2016
let power = 2 ** 3;      // 8(2 的 3 次方)
let sqrt = 16 ** 0.5;    // 4(16 的平方根)

// 幂运算等价于 Math.pow()
console.log(Math.pow(2, 3));  // 8

一元运算符

javascript
// 一元加号 (+)
let str = '123';
console.log(+str);       // 123(转换为数字)
console.log(+'abc');     // NaN
console.log(+true);      // 1
console.log(+false);     // 0

// 一元减号 (-)
console.log(-str);       // -123
console.log(-(-123));    // 123

// 递增运算符 (++)
let a = 5;
console.log(a++);        // 5(先返回,后递增)
console.log(a);          // 6

let b = 5;
console.log(++b);        // 6(先递增,后返回)
console.log(b);          // 6

// 递减运算符 (--)
let c = 5;
console.log(c--);        // 5(先返回,后递减)
console.log(c);          // 4

let d = 5;
console.log(--d);        // 4(先递减,后返回)
console.log(d);          // 4

// 实际应用
let count = 0;
count++;  // count 变为 1
count--;  // count 变为 0

字符串拼接

javascript
// 加号用于字符串拼接
let firstName = '张';
let lastName = '三';
let fullName = firstName + lastName;  // '张三'

// 数字与字符串拼接
let age = 25;
let message = '年龄:' + age;  // '年龄:25'

// 连续拼接
let result = '结果是:' + 10 + 20;  // '结果是:1020'(从左到右拼接)
let result2 = 10 + 20 + '是结果';  // '30是结果'(先计算数字)

// 使用括号改变优先级
let result3 = '结果是:' + (10 + 20);  // '结果是:30'

// 模板字符串(推荐)
let name = '张三';
let greeting = `你好,${name}!`;  // '你好,张三!'

赋值运算符

基本赋值运算符

javascript
// 简单赋值 (=)
let x = 10;

// 链式赋值
let a, b, c;
a = b = c = 10;  // a, b, c 都等于 10

// 复合赋值运算符
let num = 10;

// 加法赋值 (+=)
num += 5;   // 等价于 num = num + 5; 结果:15

// 减法赋值 (-=)
num -= 3;   // 等价于 num = num - 3; 结果:12

// 乘法赋值 (*=)
num *= 2;   // 等价于 num = num * 2; 结果:24

// 除法赋值 (/=)
num /= 4;   // 等价于 num = num / 4; 结果:6

// 取余赋值 (%=)
num %= 4;   // 等价于 num = num % 4; 结果:2

// 幂赋值 (**=) - ES2016
num **= 3;  // 等价于 num = num ** 3; 结果:8

// 字符串拼接赋值
let str = 'Hello';
str += ' World';  // 'Hello World'

解构赋值(ES6)

javascript
// 数组解构
let [a, b, c] = [1, 2, 3];
console.log(a, b, c);  // 1 2 3

// 跳过某些值
let [first, , third] = [1, 2, 3];
console.log(first, third);  // 1 3

// 默认值
let [x, y, z = 10] = [1, 2];
console.log(x, y, z);  // 1 2 10

// 剩余元素
let [head, ...tail] = [1, 2, 3, 4, 5];
console.log(head);  // 1
console.log(tail);  // [2, 3, 4, 5]

// 对象解构
let person = { name: '张三', age: 25 };
let { name, age } = person;
console.log(name, age);  // 张三 25

// 重命名变量
let { name: userName, age: userAge } = person;
console.log(userName, userAge);  // 张三 25

// 默认值
let { name, city = '北京' } = person;
console.log(city);  // 北京

// 嵌套解构
let user = {
    id: 1,
    info: {
        name: '张三',
        address: {
            city: '北京'
        }
    }
};
let { info: { name, address: { city } } } = user;
console.log(name, city);  // 张三 北京

比较运算符

比较运算符用于比较两个值,返回布尔值。

相等比较

javascript
// 相等 (==):宽松相等,会进行类型转换
console.log(5 == 5);      // true
console.log(5 == '5');    // true(字符串转换为数字)
console.log(0 == '');     // true
console.log(0 == false);  // true
console.log(null == undefined);  // true

// 不相等 (!=)
console.log(5 != 3);      // true
console.log(5 != '5');    // false

// 严格相等 (===):不会进行类型转换
console.log(5 === 5);     // true
console.log(5 === '5');   // false(类型不同)
console.log(0 === '');    // false
console.log(0 === false); // false
console.log(null === undefined);  // false

// 严格不相等 (!==)
console.log(5 !== '5');   // true
console.log(5 !== 5);     // false

// 推荐使用严格相等 ===
// 避免类型转换带来的意外结果

// 对象比较(比较引用地址)
let obj1 = { name: '张三' };
let obj2 = { name: '张三' };
let obj3 = obj1;

console.log(obj1 == obj2);   // false(不同对象)
console.log(obj1 === obj2);  // false
console.log(obj1 === obj3);  // true(同一引用)

// 数组比较
let arr1 = [1, 2, 3];
let arr2 = [1, 2, 3];
console.log(arr1 == arr2);   // false
console.log(arr1 === arr2);  // false

大小比较

javascript
// 大于 (>)
console.log(10 > 5);      // true
console.log(10 > 10);     // false
console.log('b' > 'a');   // true(字符串按字典序比较)

// 小于 (<)
console.log(5 < 10);      // true
console.log('a' < 'b');   // true

// 大于等于 (>=)
console.log(10 >= 10);    // true
console.log(10 >= 5);     // true

// 小于等于 (<=)
console.log(5 <= 5);      // true
console.log(5 <= 10);     // true

// 字符串比较
console.log('abc' < 'abd');   // true
console.log('abc' < 'abcd');  // true(短字符串较小)
console.log('ABC' < 'abc');   // true(大写字母 ASCII 码更小)

// 不同类型比较(会进行类型转换)
console.log('10' > 5);    // true('10' 转换为 10)
console.log('abc' > 5);   // false('abc' 转换为 NaN)

// 特殊情况
console.log(null > 0);    // false
console.log(null == 0);   // false
console.log(null >= 0);   // true(null 转换为 0)

console.log(undefined > 0);  // false
console.log(undefined < 0);  // false

逻辑运算符

逻辑运算符用于布尔值的逻辑运算。

基本逻辑运算

javascript
// 逻辑与 (&&):两个操作数都为 true 时返回 true
console.log(true && true);    // true
console.log(true && false);   // false
console.log(false && true);   // false
console.log(false && false);  // false

// 逻辑或 (||):至少一个操作数为 true 时返回 true
console.log(true || true);    // true
console.log(true || false);   // true
console.log(false || true);   // true
console.log(false || false);  // false

// 逻辑非 (!):取反
console.log(!true);   // false
console.log(!false);  // true
console.log(!!true);  // true(双重否定,转换为布尔值)

// 优先级:! > && > ||
console.log(true || false && false);  // true(&& 先执行)
console.log((true || false) && false); // false

短路求值

javascript
// && 短路:第一个为 false 时,不计算第二个
let a = 0;
false && (a = 1);
console.log(a);  // 0(赋值未执行)

// || 短路:第一个为 true 时,不计算第二个
let b = 0;
true || (b = 1);
console.log(b);  // 0(赋值未执行)

// 利用短路设置默认值
let userName = '';
let displayName = userName || '匿名用户';  // '匿名用户'

let userAge = 0;
let displayAge = userAge || 18;  // 18(注意:0 是假值)

// 使用 ?? 空值合并运算符(ES2020)
// 只在 null 或 undefined 时使用默认值
let age = 0;
let displayAge2 = age ?? 18;  // 0(0 不是 null/undefined)

let value = null;
let result = value ?? '默认值';  // '默认值'

let value2 = undefined;
let result2 = value2 ?? '默认值';  // '默认值'

逻辑运算返回值

javascript
// && 返回第一个假值或最后一个值
console.log(1 && 2);        // 2
console.log(0 && 2);        // 0
console.log(1 && 2 && 3);   // 3
console.log(1 && 0 && 3);   // 0

// || 返回第一个真值或最后一个值
console.log(1 || 2);        // 1
console.log(0 || 2);        // 2
console.log(0 || '' || 3);  // 3
console.log(0 || '' || null);  // null

// 实际应用
let user = {
    name: '张三',
    settings: {
        theme: 'dark'
    }
};

// 安全访问嵌套属性
let theme = user && user.settings && user.settings.theme;  // 'dark'

// 可选链运算符 (?.) - ES2020
let theme2 = user?.settings?.theme;  // 'dark'

let admin = null;
let adminTheme = admin?.settings?.theme;  // undefined(不会报错)

条件(三元)运算符

javascript
// 语法:条件 ? 表达式1 : 表达式2
// 条件为 true 返回表达式1,否则返回表达式2

let age = 18;
let status = age >= 18 ? '成年' : '未成年';
console.log(status);  // '成年'

// 嵌套三元运算符
let score = 85;
let grade = score >= 90 ? 'A' :
            score >= 80 ? 'B' :
            score >= 70 ? 'C' :
            score >= 60 ? 'D' : 'F';
console.log(grade);  // 'B'

// 实际应用:显示不同内容
let isLoggedIn = true;
let welcomeMessage = isLoggedIn ? '欢迎回来!' : '请先登录';
console.log(welcomeMessage);

// 设置默认值
let userInput = '';
let displayName = userInput ? userInput : '匿名用户';
console.log(displayName);  // '匿名用户'

// 条件渲染
let items = [];
let html = items.length > 0 ? 
    `<ul>${items.map(item => `<li>${item}</li>`).join('')}</ul>` : 
    '<p>暂无数据</p>';

位运算符

位运算符将操作数视为 32 位二进制数进行运算。

基本位运算

javascript
// 按位与 (&):两位都为 1 时结果为 1
console.log(5 & 3);   // 1
// 5: 0101
// 3: 0011
// &: 0001 = 1

// 按位或 (|):至少一位为 1 时结果为 1
console.log(5 | 3);   // 7
// 5: 0101
// 3: 0011
// |: 0111 = 7

// 按位异或 (^):两位不同时结果为 1
console.log(5 ^ 3);   // 6
// 5: 0101
// 3: 0011
// ^: 0110 = 6

// 按位非 (~):反转所有位
console.log(~5);  // -6
// 5:  00000000000000000000000000000101
// ~5: 11111111111111111111111111111010 = -6(补码表示)

// 左移 (<<):所有位向左移动,低位补 0
console.log(5 << 1);  // 10(5 * 2)
console.log(5 << 2);  // 20(5 * 4)

// 右移 (>>):所有位向右移动,高位补符号位
console.log(10 >> 1);  // 5(10 / 2)
console.log(-10 >> 1); // -5(保持符号)

// 无符号右移 (>>>):高位补 0
console.log(-10 >>> 1);  // 2147483643(大正数)

位运算应用

javascript
// 判断奇偶
function isOdd(n) {
    return n & 1;  // 奇数返回 1,偶数返回 0
}
console.log(isOdd(5));  // 1(奇数)
console.log(isOdd(4));  // 0(偶数)

// 取整(向下取整)
console.log(~~3.7);   // 3
console.log(3.7 | 0); // 3

// 交换两个数(不使用临时变量)
let a = 5, b = 3;
a = a ^ b;
b = a ^ b;
a = a ^ b;
console.log(a, b);  // 3 5

// 权限判断(位掩码)
const READ = 1;     // 0001
const WRITE = 2;    // 0010
const EXECUTE = 4;  // 0100

let permission = READ | WRITE;  // 0011

// 检查权限
console.log(permission & READ);     // 1(有读权限)
console.log(permission & EXECUTE);  // 0(无执行权限)

// 添加权限
permission |= EXECUTE;

// 移除权限
permission &= ~WRITE;

其他运算符

typeof 运算符

javascript
// typeof 返回数据类型的字符串
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'
console.log(typeof {});           // 'object'
console.log(typeof []);           // 'object'
console.log(typeof function(){}); // 'function'

// typeof 的括号可选
console.log(typeof 42);       // 'number'
console.log(typeof(42));      // 'number'

// 检测未声明的变量
console.log(typeof undeclaredVar);  // 'undefined'(不会报错)

instanceof 运算符

javascript
// instanceof 检测对象是否是某个构造函数的实例
console.log([] instanceof Array);    // true
console.log([] instanceof Object);   // true
console.log({} instanceof Object);   // true
console.log(new Date() instanceof Date);  // true

// 自定义构造函数
function Person(name) {
    this.name = name;
}
let person = new Person('张三');
console.log(person instanceof Person);  // true
console.log(person instanceof Object);  // true

in 运算符

javascript
// in 检查属性是否存在于对象中
let person = { name: '张三', age: 25 };

console.log('name' in person);   // true
console.log('city' in person);   // false

// 检查继承的属性
console.log('toString' in person);  // true(继承自 Object)

// 检查数组索引
let arr = ['a', 'b', 'c'];
console.log(0 in arr);  // true
console.log(3 in arr);  // false

delete 运算符

javascript
// delete 删除对象属性
let person = { name: '张三', age: 25 };
console.log(delete person.age);  // true(删除成功)
console.log(person);  // { name: '张三' }

// 删除不存在的属性返回 true
console.log(delete person.city);  // true

// 不能删除 var 声明的变量
var x = 10;
console.log(delete x);  // false
console.log(x);  // 10

// 不能删除内置属性
console.log(delete Math.PI);  // false

// 删除数组元素
let arr = [1, 2, 3];
delete arr[1];
console.log(arr);  // [1, empty, 3]
console.log(arr.length);  // 3(长度不变)

逗号运算符

javascript
// 逗号运算符执行多个表达式,返回最后一个表达式的值
let x = (1, 2, 3);
console.log(x);  // 3

// 在 for 循环中使用
for (let i = 0, j = 10; i < j; i++, j--) {
    console.log(i, j);
}

// 函数返回多个值
function getCoordinates() {
    let x = 10, y = 20;
    return (x++, y++, { x, y });
}
console.log(getCoordinates());  // { x: 11, y: 21 }

void 运算符

javascript
// void 计算表达式但不返回值(返回 undefined)
console.log(void 0);        // undefined
console.log(void(1 + 1));   // undefined

// 常用于阻止链接的默认行为
// <a href="javascript:void(0)" onclick="doSomething()">点击</a>

// 立即执行函数表达式(IIFE)
void function() {
    console.log('执行了');
}();

展开运算符(ES6)

javascript
// 展开数组
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let combined = [...arr1, ...arr2];
console.log(combined);  // [1, 2, 3, 4, 5, 6]

// 复制数组
let copy = [...arr1];
console.log(copy);  // [1, 2, 3]

// 展开对象
let obj1 = { a: 1, b: 2 };
let obj2 = { c: 3, ...obj1 };
console.log(obj2);  // { c: 3, a: 1, b: 2 }

// 函数参数展开
function sum(a, b, c) {
    return a + b + c;
}
let nums = [1, 2, 3];
console.log(sum(...nums));  // 6

剩余运算符(ES6)

javascript
// 收集剩余参数
function sum(...args) {
    return args.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4, 5));  // 15

// 与普通参数结合
function greet(greeting, ...names) {
    names.forEach(name => {
        console.log(`${greeting}, ${name}!`);
    });
}
greet('你好', '张三', '李四', '王五');

// 解构中的剩余元素
let [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first);   // 1
console.log(second);  // 2
console.log(rest);    // [3, 4, 5]

运算符优先级

javascript
// 运算符优先级从高到低(部分)

// 1. 括号 ()
// 2. 成员访问 . []
// 3. 函数调用 ()
// 4. new
// 5. 后置递增/递减 ++ --
// 6. 逻辑非 !、按位非 ~、一元运算符 + -、typeof、void、delete
// 7. 幂 **
// 8. 乘、除、取余 * / %
// 9. 加、减 + -
// 10. 位移 << >> >>>
// 11. 比较 < <= > >= in instanceof
// 12. 相等 == != === !==
// 13. 按位与 &
// 14. 按位异或 ^
// 15. 按位或 |
// 16. 逻辑与 &&
// 17. 逻辑或 ||
// 18. 空值合并 ??
// 19. 条件(三元) ?:
// 20. 赋值 = += -= *= /= 等
// 21. 展开 ...
// 22. 逗号 ,

// 示例
let result = 2 + 3 * 4;     // 14(先乘后加)
let result2 = (2 + 3) * 4;  // 20(括号优先)

let x = 5;
let y = x++ + ++x;  // 5 + 7 = 12
// x++ 返回 5,x 变为 6
// ++x 返回 7,x 变为 7

// 使用括号明确优先级
let complex = ((a > b) && (c < d)) || (e === f);

小结

本章学习了 JavaScript 的各种运算符:

  • 算术运算符:+、-、*、/、%、**、++、--
  • 赋值运算符:=、+=、-=、*=、/=、%=、**=
  • 比较运算符:==、===、!=、!==、>、<、>=、<=
  • 逻辑运算符:&&、||、!
  • 条件运算符:? :
  • 位运算符:&、|、^、~、<<、>>、>>>
  • 其他运算符:typeof、instanceof、in、delete、逗号、展开、剩余

下一章我们将学习 流程控制,了解如何控制代码的执行流程。