蓝姿 發表於 2025-5-26 10:39:00

Web前端入门第 58 问:JavaScript 运算符 == 和 === 有什么区别?

<h2 id="运算符">运算符</h2>
<p>JavaScript 运算符是真的多,尤其是 ES6 之后还在不停的加运算符,其他编程语言看 JS 就像怪物一样,各种骚操作不断~~</p>
<h3 id="运算符分类">运算符分类</h3>
<p><strong>1、算术运算符</strong></p>
<p>算术运算符的作用就是用来基础计算,跟小学课本一样,包含:加 <code>+</code>,减 <code>-</code>,乘 <code>*</code>,除 <code>/</code>,取余(也叫做取模) <code>%</code>,指数 <code>**</code>,自增 <code>++</code>,自减 <code>--</code>。</p>
<p>只是需注意:乘号不再是 <code>x</code>,除号也不再是 <code>÷</code>!</p>
<p>与我们学过的运算法则一样,乘法与除法优先级比加减法高,如果要改变优先级,需要使用括号 <code>()</code>,只是一个算式中有多个括号还是使用小括号,<code>不用中括号</code>而已。</p>
<pre><code class="language-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
</code></pre>
<p><strong>2、比较运算符</strong></p>
<p>一般用于逻辑比较,比如比较两个值是否相等,比较两个数的大小等等。包含:等于 <code>==</code>,严格等于(全等于) <code>===</code>,不等于 <code>!=</code>,严格不等于(不全等) <code>!==</code>,大于 <code>&gt;</code>,小于 <code>&lt;</code>,大于等于 <code>&gt;=</code>,小于等于 <code>&lt;=</code></p>
<p>需特别注意:<code>==</code> 与 <code>!=</code> 会存在类型转换,所以 JS 建议使用 <code>===</code> 与 <code>!==</code>。</p>
<pre><code class="language-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 &gt; 2);    // true
console.log('apple' &gt; 'banana');    // false(按字母顺序比较)

console.log(2 &gt;= 2);    // true
console.log(2 &lt;= 2);    // true
</code></pre>
<p>如果要比较值类型不同,建议显示转换类型再用 <code>===</code> 比较。比如:</p>
<pre><code class="language-js">const a = 5;
const b = '5';

if (a + '' === '5') {} // 将 a 转换为字符串再比较

if (b - 0 === 5) {} // 将 b 转换为数字再比较
</code></pre>
<p><strong>3、逻辑运算符</strong></p>
<p>用于逻辑判断,包含:逻辑与 <code>&amp;&amp;</code>,逻辑或 <code>||</code>,逻辑非 <code>!</code>。</p>
<p>需注意他们的短路特性。</p>
<pre><code class="language-js">// 逻辑与(&amp;&amp;):短路特性
console.log(true &amp;&amp; 'Hello');    // 'Hello'(返回最后一个真值)
console.log(false &amp;&amp; '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 &amp;&amp; console.log('执行了!'); // 输出 '执行了!'
false || console.log('执行了!'); // 输出 '执行了!'
</code></pre>
<p><strong>4、赋值运算符</strong></p>
<p>用于给变量赋值,包含:赋值(等于) <code>=</code>,加等于(累加) <code>+=</code>,减等于(累减) <code>-=</code>,乘等于(累乘) <code>*=</code>,除等于(累除) <code>/=</code>,模等于(累模) <code>%=</code>,幂等于(累幂) <code>**=</code>。</p>
<pre><code class="language-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
</code></pre>
<p><strong>5、位运算符</strong></p>
<p>二进制的位运算符,据说是最快的运算符,当然一般编程用不上,如果您用 JS 进行大量的计算操作时,比如:图形图像算法、加密算法等相关操作,这时候就必须需掌握位运算了!包含:按位与 <code>&amp;</code>,按位或 <code>|</code>,按位异或 <code>^</code>,按位非 <code>~</code>,左移 <code>&lt;&lt;</code>,右移 <code>&gt;&gt;</code>,无符号右移 <code>&gt;&gt;&gt;</code>。</p>
<p>这部分运算符涉及到底层的二进制运算,如果有兴趣可以查找相关资料学习。</p>
<pre><code class="language-js">// 按位与(&amp;)
console.log(5 &amp; 3);      // 1(二进制 101 &amp; 011 → 001)

// 按位或(|)
console.log(5 | 3);      // 7(101 | 011 → 111)

// 无符号右移(&gt;&gt;&gt;)
console.log(-1 &gt;&gt;&gt; 0);   // 4294967295(将负数转为无符号整数)
</code></pre>
<p><strong>6、三元运算符</strong></p>
<p>又称为三目运算符(<em>吐槽下:乱七八糟的名字特多</em>),一般用于简化 <code>if else</code> 语句,但不建议过多嵌套,要不然代码阅读起来费劲。</p>
<p>语法:<code>condition ? expr1 : expr2</code>。</p>
<pre><code class="language-js">const age = 20;
const canVote = age &gt;= 18 ? 'Yes' : 'No';
console.log(canVote); // 'Yes'

// 等价于
if (age &gt;= 18) {
console.log('Yes');
} else {
console.log('No');
}

// 三元运算符的多次嵌套
const a = age &gt; 80 ? '高龄老人' : (age &gt; 60 ? '老年人' : (age &gt; 40 ? '中年人' : '年轻人'))
</code></pre>
<p>可以看看多次嵌套的代码是否是难以阅读,为了项目的可维护性,真心不建议把三元运算符用于多次嵌套。</p>
<p><strong>7、特殊运算符</strong></p>
<p>JS 内置的关键字,包含:<code>typeof</code>, <code>instanceof</code>, <code>delete</code>, <code>void</code>, <code>in</code>, <code>new</code>。</p>
<pre><code class="language-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. 返回新对象   */
</code></pre>
<p><strong>8、ES6+ 运算符</strong></p>
<p>ES6 之后新增的一些运算符,骚操作从这里开始。包含:展开运算符 <code>...</code>, 可选链 <code>?.</code>, 空值合并 <code>??</code></p>
<pre><code class="language-js">// 展开运算符(...)
const arr1 = ;
const arr2 = [...arr1, 4, 5, 6];
console.log(...arr1); // 1 2 3
console.log(arr2); //

// 可选链(?.)
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)
</code></pre>
<h3 id="类型转换规则">类型转换规则</h3>
<p>当操作数类型不同时,JS 会按内部规则尝试进行类型转换:</p>
<pre><code class="language-js">const obj = { toString: () =&gt; '100' };
// 调用 valueOf() → toString(),若结果为原始值则继续比较
console.log(obj &gt; 50); // true('100' → 100 &gt; 50)

// true → 1,false → 0
console.log(true &gt; -1); // true(1 &gt; -1)
console.log(false &lt; 1);// true(0 &lt; 1)

// null → 0
console.log(null &gt; -1); // true(0 &gt; -1)

// undefined → NaN
console.log(undefined &gt; 0); // false(NaN 与任何值比较均为 false)

// 若字符串为合法数字 → 转换为数字,否则 → NaN
console.log('123' &gt; 50);   // true(123 &gt; 50)
console.log('abc' &gt; 0);    // false('abc' → NaN)

// 对象与非对象比较
const arr = ;
console.log(arr &gt; 5); // true(.toString() → '10' → 10 &gt; 5)

// 十六进制字符串
console.log('0x1f' &gt; 30); // true('0x1f' → 31 &gt; 30)

// 空字符串与 0
console.log('' &gt; -1);   // true('' → 0 &gt; -1)
console.log(0 == '');   // true(0 == 0)

// 布尔值的陷阱
console.log(true == '1');   // true(1 == 1)
console.log(false == '0');// true(0 == 0)

console.log( &gt; 0);      // true(.toString() → '1' → 1 &gt; 0)
console.log([] &gt; -1);      // true([].toString() → '' → 0 &gt; -1)
console.log([] == 0);      // true(0 == 0)
console.log([] == false);// true(0 == 0)
</code></pre>
<h2 id="常见问题">常见问题</h2>
<p>1、== 和 === 的区别是什么?</p>
<p>答:== 会进行类型转换后比较,=== 严格比较值和类型。</p>
<p>2、逻辑运算符 &amp;&amp; 和 || 的返回值是什么?</p>
<p>答:返回第一个决定表达式结果的子表达式值(短路求值)。</p>
<p>3、1 + '1' 和 '1' + 1 的结果是什么?</p>
<p>答:均为 '11'(字符串拼接)。</p>
<p>4、0 == false 和 '' == false 的结果是什么?为什么?</p>
<p>答:均为 true,因 == 会进行隐式转换。</p>
<p>5、typeof null 返回什么?为什么?</p>
<p>答:'object'(历史遗留问题)。</p>
<p>6、可选链 ?. 和空值合并 ?? 的作用是什么?</p>
<p>答:obj?.prop 避免访问 null/undefined,a ?? b 仅在 a 为 null/undefined 时返回 b。</p>
<p>7、以下代码的输出是什么?</p>
<pre><code class="language-js">console.log(1 &lt; 2 &lt; 3); // true(等价于 (1 &lt; 2) &lt; 3 → true &lt; 3 → 1 &lt; 3 → true)
console.log(3 &gt; 2 &gt; 1); // false(等价于 (3 &gt; 2) &gt; 1 → true &gt; 1 → 1 &gt; 1 → false)
</code></pre>
<p>8、<code>console.log(!!' ')</code> 的输出是什么?</p>
<p>答:true(非空字符串转布尔值为 true)。</p>
<p>9、如何用短路求值简化代码?</p>
<pre><code class="language-js">const value = input || defaultValue;
</code></pre>
<p>10、如何安全访问嵌套对象属性?</p>
<p>答:使用可选链 obj?.a?.b ?? 'default'。</p>
<h2 id="写在最后">写在最后</h2>
<p>优先使用 <code>===</code> 和 <code>!==</code> 避免 JS 的隐式转换带来的不确定性。</p>
<p>隐式转换机制需特别注意,特别是在处理用户输入、API 接口响应数据时,稍不注意就掉坑了!!</p>
<p>如果您有大量计算工作量,那么必须啃书二进制的位运算符,否则使用十进制运算会拖慢程序运行速度。</p>


</div>
<div id="MySignature" role="contentinfo">
    <p>&nbsp;</p>
<p style="font-size: 18px;font-weight: bold;">文章首发于微信公众号【<span style="color:rgb(255, 71, 87)">前端路引</span>】,欢迎 <span style="color:#4ec259">微信扫一扫</span> 查看更多文章。</p>
<p>
<img style="max-width: 320px;" src="https://images.cnblogs.com/cnblogs_com/linx/2447020/o_250228035031_%E5%85%AC%E4%BC%97%E5%8F%B7%E4%BA%8C%E7%BB%B4%E7%A0%81.png"/>
</p>
<p>本文来自博客园,作者:前端路引,转载请注明原文链接:https://www.cnblogs.com/linx/p/18896521</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/linx/p/18896521
頁: [1]
查看完整版本: Web前端入门第 58 问:JavaScript 运算符 == 和 === 有什么区别?