JavaScript 运算符 == 和 === 有什么区别?

笔记哥 / 05-26 / 30点赞 / 0评论 / 642阅读
## 运算符 JavaScript 运算符是真的多,尤其是 ES6 之后还在不停的加运算符,其他编程语言看 JS 就像怪物一样,各种骚操作不断~~ ### 运算符分类 **1、算术运算符** 算术运算符的作用就是用来基础计算,跟小学课本一样,包含:加 `+`,减 `-`,乘 `*`,除 `/`,取余(也叫做取模) `%`,指数 `**`,自增 `++`,自减 `--`。 只是需注意:乘号不再是 `x`,除号也不再是 `÷`! 与我们学过的运算法则一样,乘法与除法优先级比加减法高,如果要改变优先级,需要使用括号 `()`,只是一个算式中有多个括号还是使用小括号,`不用中括号`而已。 ```js // 加法 console.log(3 + 5); // 8 console.log(3 + '5'); // '35'(字符串拼接) // 减法、乘法、除法 console.log(10 - 3); // 7 console.log(2 * 4); // 8 console.log(10 / 2); // 5 // 取余、指数 console.log(10 % 3); // 1(余数) console.log(2 ** 3); // 8(2的3次方) // 自增/自减(注意前置与后置) let a = 5; console.log(a++); // 5(先返回原值,再自增) console.log(++a); // 7(先自增,再返回新值) // 使用括号改变优先级 console.log((2 + 3) * 4); // 5 * 4 = 20 console.log(((2 + 3) - (5 -3)) * 4); // (5 - 2) * 4 = 12 ``` **2、比较运算符** 一般用于逻辑比较,比如比较两个值是否相等,比较两个数的大小等等。包含:等于 `==`,严格等于(全等于) `===`,不等于 `!=`,严格不等于(不全等) `!==`,大于 `>`,小于 `<`,大于等于 `>=`,小于等于 `<=` 需特别注意:`==` 与 `!=` 会存在类型转换,所以 JS 建议使用 `===` 与 `!==`。 ```js // 松散比较(类型转换) console.log(5 == '5'); // true(值相等) console.log(0 == false); // true(0和false在松散比较中等价) console.log(5 != '5'); // false(值相等) // 严格比较(值和类型) console.log(5 === '5'); // false(类型不同) console.log(0 === false); // false(类型不同) console.log(5 !== '5'); // true(类型不同) // 其他比较 console.log(3 > 2); // true console.log('apple' > 'banana'); // false(按字母顺序比较) console.log(2 >= 2); // true console.log(2 <= 2); // true ``` 如果要比较值类型不同,建议显示转换类型再用 `===` 比较。比如: ```js const a = 5; const b = '5'; if (a + '' === '5') {} // 将 a 转换为字符串再比较 if (b - 0 === 5) {} // 将 b 转换为数字再比较 ``` **3、逻辑运算符** 用于逻辑判断,包含:逻辑与 `&&`,逻辑或 `||`,逻辑非 `!`。 需注意他们的短路特性。 ```js // 逻辑与(&&):短路特性 console.log(true && 'Hello'); // 'Hello'(返回最后一个真值) console.log(false && 'Hello'); // false(遇到假值直接返回) // 逻辑或(||):短路特性 console.log(0 || 'default'); // 'default'(返回第一个真值) console.log('A' || 'B'); // 'A' // 逻辑非(!) console.log(!true); // false console.log(!!'非空字符串'); // true(强制转布尔值) // 应用场景 // 默认值设置 function greet(name) { name = name || 'Guest'; // 若 name 为假值,返回 'Guest' console.log(`Hello, ${name}!`); } greet(); // 'Hello, Guest!' // 条件执行函数 true && console.log('执行了!'); // 输出 '执行了!' false || console.log('执行了!'); // 输出 '执行了!' ``` **4、赋值运算符** 用于给变量赋值,包含:赋值(等于) `=`,加等于(累加) `+=`,减等于(累减) `-=`,乘等于(累乘) `*=`,除等于(累除) `/=`,模等于(累模) `%=`,幂等于(累幂) `**=`。 ```js let x = 10; x += 5; // x = x + 5 → 15 x *= 2; // x = 15 * 2 → 30 x **= 2; // x = 30^2 → 900 console.log(x); // 900 ``` **5、位运算符** 二进制的位运算符,据说是最快的运算符,当然一般编程用不上,如果您用 JS 进行大量的计算操作时,比如:图形图像算法、加密算法等相关操作,这时候就必须需掌握位运算了!包含:按位与 `&`,按位或 `|`,按位异或 `^`,按位非 `~`,左移 `<<`,右移 `>>`,无符号右移 `>>>`。 这部分运算符涉及到底层的二进制运算,如果有兴趣可以查找相关资料学习。 ```js // 按位与(&) console.log(5 & 3); // 1(二进制 101 & 011 → 001) // 按位或(|) console.log(5 | 3); // 7(101 | 011 → 111) // 无符号右移(>>>) console.log(-1 >>> 0); // 4294967295(将负数转为无符号整数) ``` **6、三元运算符** 又称为三目运算符(*吐槽下:乱七八糟的名字特多*),一般用于简化 `if else` 语句,但不建议过多嵌套,要不然代码阅读起来费劲。 语法:`condition ? expr1 : expr2`。 ```js const age = 20; const canVote = age >= 18 ? 'Yes' : 'No'; console.log(canVote); // 'Yes' // 等价于 if (age >= 18) { console.log('Yes'); } else { console.log('No'); } // 三元运算符的多次嵌套 const a = age > 80 ? '高龄老人' : (age > 60 ? '老年人' : (age > 40 ? '中年人' : '年轻人')) ``` 可以看看多次嵌套的代码是否是难以阅读,为了项目的可维护性,真心不建议把三元运算符用于多次嵌套。 **7、特殊运算符** JS 内置的关键字,包含:`typeof`, `instanceof`, `delete`, `void`, `in`, `new`。 ```js // typeof 返回变量的类型字符串 console.log(typeof 42); // 'number' console.log(typeof null); // 'object'(历史遗留问题) // instanceof 检查对象是否是某个构造函数的实例(基于原型链) class Person {} const p = new Person(); console.log(p instanceof Person); // true // delete 删除对象的属性或数组元素(对变量无效) const obj = { a: 1 }; delete obj.a; // 删除属性 console.log(obj.a); // undefined // void 执行表达式并返回 undefined console.log(void (1 + 1)); // undefined // in 检查对象或其原型链中是否包含指定属性 console.log('toString' in obj); // true(继承自Object.prototype) // new 创建构造函数实例(调用构造函数,绑定 this) function Car(brand) { this.brand = brand; } const myCar = new Car('Tesla'); console.log(myCar.brand); // 'Tesla' /* 等价于以下过程: 1. 创建一个空对象 {} 2. 将空对象的原型指向 Car.prototype 3. 执行 Car 函数,this 指向该空对象 4. 返回新对象 */ ``` **8、ES6+ 运算符** ES6 之后新增的一些运算符,骚操作从这里开始。包含:展开运算符 `...`, 可选链 `?.`, 空值合并 `??` ```js // 展开运算符(...) const arr1 = [1, 2, 3]; const arr2 = [...arr1, 4, 5, 6]; console.log(...arr1); // 1 2 3 console.log(arr2); // [1, 2, 3, 4, 5, 6] // 可选链(?.) const user = { address: { city: 'Paris' } }; console.log(user?.address?.city); // 'Paris' console.log(user?.phone?.number); // undefined(不会报错) // 空值合并(??) const input = null; const value = input ?? 'default'; // 'default'(仅针对 null/undefined) ``` ### 类型转换规则 当操作数类型不同时,JS 会按内部规则尝试进行类型转换: ```js const obj = { toString: () => '100' }; // 调用 valueOf() → toString(),若结果为原始值则继续比较 console.log(obj > 50); // true('100' → 100 > 50) // true → 1,false → 0 console.log(true > -1); // true(1 > -1) console.log(false < 1); // true(0 < 1) // null → 0 console.log(null > -1); // true(0 > -1) // undefined → NaN console.log(undefined > 0); // false(NaN 与任何值比较均为 false) // 若字符串为合法数字 → 转换为数字,否则 → NaN console.log('123' > 50); // true(123 > 50) console.log('abc' > 0); // false('abc' → NaN) // 对象与非对象比较 const arr = [10]; console.log(arr > 5); // true([10].toString() → '10' → 10 > 5) // 十六进制字符串 console.log('0x1f' > 30); // true('0x1f' → 31 > 30) // 空字符串与 0 console.log('' > -1); // true('' → 0 > -1) console.log(0 == ''); // true(0 == 0) // 布尔值的陷阱 console.log(true == '1'); // true(1 == 1) console.log(false == '0'); // true(0 == 0) console.log([1] > 0); // true([1].toString() → '1' → 1 > 0) console.log([] > -1); // true([].toString() → '' → 0 > -1) console.log([] == 0); // true(0 == 0) console.log([] == false); // true(0 == 0) ``` ## 常见问题 1、== 和 === 的区别是什么? 答:== 会进行类型转换后比较,=== 严格比较值和类型。 2、逻辑运算符 && 和 || 的返回值是什么? 答:返回第一个决定表达式结果的子表达式值(短路求值)。 3、1 + '1' 和 '1' + 1 的结果是什么? 答:均为 '11'(字符串拼接)。 4、0 == false 和 '' == false 的结果是什么?为什么? 答:均为 true,因 == 会进行隐式转换。 5、typeof null 返回什么?为什么? 答:'object'(历史遗留问题)。 6、可选链 ?. 和空值合并 ?? 的作用是什么? 答:obj?.prop 避免访问 null/undefined,a ?? b 仅在 a 为 null/undefined 时返回 b。 7、以下代码的输出是什么? ```js console.log(1 < 2 < 3); // true(等价于 (1 < 2) < 3 → true < 3 → 1 < 3 → true) console.log(3 > 2 > 1); // false(等价于 (3 > 2) > 1 → true > 1 → 1 > 1 → false) ``` 8、`console.log(!!' ')` 的输出是什么? 答:true(非空字符串转布尔值为 true)。 9、如何用短路求值简化代码? ```js const value = input || defaultValue; ``` 10、如何安全访问嵌套对象属性? 答:使用可选链 obj?.a?.b ?? 'default'。 ## 写在最后 优先使用 `===` 和 `!==` 避免 JS 的隐式转换带来的不确定性。 隐式转换机制需特别注意,特别是在处理用户输入、API 接口响应数据时,稍不注意就掉坑了!! 如果您有大量计算工作量,那么必须啃书二进制的位运算符,否则使用十进制运算会拖慢程序运行速度。