探寻 JavaScript 逻辑运算符(与、或)的真谛

 十二月已经过半,冬季是一个美妙的季节,寒冷的空气逼得人们不得不躲在安逸舒适的环境里生活。冬季会给人一种安静祥和的氛围,让人沉浸在其中,仿佛是一个旧的阶段的结束,同时也是一个新的阶段的开始。这么说来,西方和中国的圣诞节和春节都选择在了冬季也不是没有道理,在一年中最寒冷的时候,人们拥簇在温暖的环境里,彼此诉说着过去一年里自己的成就,展望着新的一年里美好的愿望,相互挂念的人团聚,天气的寒冷和人情的温暖形成了强烈的对比。而在天寒地冻之中,仿佛更有利于人们思考,去探寻知识的真谛。

  这次想分享的是 JS 当中的逻辑运算符与、或,也就是 && 、 || ,初来乍到的同学们看到这里就会觉得没趣了,这玩意有什么好分享的,刚开始学 JS 的时候不就会了吗,我用了无数遍都没有什么问题啊。而有经验的同学可能会陷入沉思,难不成这其中会有什么奥秘所在?没错,别看这简简单单的几个运算符,虽然这是最基础的知识,但其中隐藏的奥秘却十分耐人寻味,接下来我就为大家一一揭开这简答的运算符背后的奇妙之处。

  基础的作用我就不说了,这两个符号是个程序员都能明白,这里首先我想先来说一说 JS 当中的隐式转换。

  众所周知,JS 在做逻辑判断的时候会自动将非布尔类型的值进行隐式转换,转换成布尔类型的值然后在进行逻辑运算。在初学 JS 的时候,都会讲到在隐式转换中,除了几个特定的假值,其他的均会转换成真值,这些假值有:

1 NaN;
2 "";
3 undefined;
4 null;
5 0;

  有了这些隐式转换的规则,便构成了 JS 当中逻辑运算的核心基础。

  其实在 JS 当中,要说“逻辑运算符”其实并不完全正确,Kyle Simpson 在《You Don‘t Know JS》系列书当中提到:“与其说是‘逻辑运算符’,不如说是‘选择器运算符’。” 为什么大师要这样说呢?其实我们大多数人都被 JS 的表象给蒙蔽了,比如下面一段非常简单的代码:

1 if( "hello" && 0 ) {
2     console.log(true);
3 } else {
4     console.log(false);
5 }

  如果你对 JS 了解的不够深刻,你可能会这样解释这段代码:首先在逻辑判断中,"hello" 是一个真值,0 是一个假值,一个真值和一个假值进行与运算,结果为 false 。这也可能是大多数人的理解,但其实不然,其内部的原理可不止这么简单,因为 && 和 || 返回的并不是判断条件的真假 ,而是判断条件中的一个原始值。它将依次对条件判断中的值进行判断,如果是非布尔值,则转换成布尔值做判断,然后再根据判断条件来决定返回哪一个值。

  对于 && :该运算符返回条件语句中的第一个假值,如果所有的值都为真,则返回最后一个值,&& 也被称为 “守护运算符” 。比如下面一段代码:

1 var a = "hello" && "world";
2 console.log(a);  //world
3 var b = 0 && 1;
4 console.log(b);  //0

  可以看出,逻辑运算符其实返回的并不是条件的真假,而是原始值。如果条件语句中有多个 && 运算符,则一样遵循以上原则,从左向右依次判断,如果遇到了假值,就返回该假值,如果所有值都为真,则返回最后一个值。

  对于 ||:该运算符与 && 运算符相反,它返回条件语句中的第一个真值,如果所有值都为假,则返回最后一个值。比如下面一段代码:

1 var a = "hello" || 0;
2 console.log(a);  //hello
3 var b = 0 || NaN;
4 console.log(b);  //NaN

  同样,|| 返回的也不是布尔值。如果有多个 || 则同样遵循相同的原则,从左向右依次扫描。

  讲到这里也就来到了本篇文章的核心,在 JS 当中,条件判断语句都是建立在隐式转换之上的,也就是说所谓的逻辑运算符,实际上是在条件判断语句中从左向右依次扫描,如果是一个布尔值,则判断该布尔值的真假,如果是一个非布尔值,则先对该值进行隐式转换,然后再判断真假,如果满足条件,则返回该值,如果没有满足条件值,则返回最后一个值,然后在对返回的这个值做判断,如果是一个布尔值,则直接判断,如果是一个非布尔值,则先隐式转换成布尔值,再做判断。所以我们也可以把 && 称为 “取假运算符” ,把 || 称为 “取真运算符” ,因为这两个运算符的实质都是取条件语句中的第一个真值或者假值,如果始终没有找到,则返回最后一个值。而这样的算法也恰好满足逻辑判断的需求,比如 && 运算符,如果所有的值都是真值,那么返回哪个值其实都无所谓,因为所有值都能够被隐式转化为 true ,而只要有一个假值,则判断条件不成立,所以会返回第一个遇到的假值。而 || 运算符,如果所有的值都是假值,返回任意一个都会被隐式转换成 false ,但只要遇到了一个真值,则判断条件成立,所以会返回第一个遇到的真值。&& 和 || 运算符都是 “短路” 的。

  所以我们可以自己实现一个逻辑运算的函数:

 1 // && 等价于:
 2 function AND () {
 3     for (var i = 0; i < arguments.length; i++) {
 4         if (!arguments[i]) {
 5             return arguments[i];
 6         }
 7     }
 8     return arguments[i-1];
 9 }
10
11 // || 等价于:
12 function OR () {
13     for (var i = 0; i < arguments.length; i++) {
14         if(arguments[i]) {
15             return arguments[i];
16         }
17     }
18     return arguments[i-1];
19 }

  (注:在这里我同时也想对 ! 这个运算符做讲解,但考虑到内容和篇幅的问题,暂时不做深入探究,仅做简单讲述。 ! 运算符实际上运行机制与 && 和 || 是一样的,首先会对参数值做判断,如果是一个布尔值,则进行取反运算,如果是一个非布尔值,则先进行隐式转换,再进行取反运算。而我们通常写的 if (something) 语句,实际上的意思 if (!!something))

  然后我们可以这样使用:

1 var a = ["hello", undefined, "world"];
2 console.log(AND.apply(null, a));  //undefined
3 var b = ["", 0, NaN];
4 console.log(OR.apply(null, b));  //NaN

  进而,我们就可以推断出一下结论:

1 a = x || y;
2 //等价于:
3 a = x ? x : y;
4
5 a = x && y;
6 //等价于:
7 a = x ? y : x;

  这通常也是一些压缩工具所做的事情,它们尽可能的将繁杂的条件判断语句转换成 && 或者 || ,因为这样代码更加的精简,但是可读性则就不那么可观了。

  对于最开始的那一段代码:

1 if( "hello" && 0 ) {
2     console.log(true);
3 } else {
4     console.log(false);
5 }

  我们现在就要这样解释:首先这是个与运算符,与运算符的作用是取第一个假值,如果所有的值都为真,那么则返回最后一个值。所以在这条语句中,第一个值是 "hello" ,因为该值是一个非布尔值,JS 引擎会先将它隐式转换成布尔值,而该值不在假值的范围内,所以会被转化成 true 。随后 JS 引擎会继续查找,第二个值是 0 ,该值同样也不是一个布尔值,所以 JS 引擎也会先将它隐式转换成布尔值,而该值在假值的范围内,所以会被转化成 false ,满足 && 运算符的查找条件,则将值 0 返回。而条件判断语句接受到了值 0 ,该值不是一个布尔类型的值,所以会先对它进行隐式转换,而该值在假值范围内,所以会被转化成 false ,然后控制台会输出 false。

  所以说以后当我们看到 && 和 || 时候,就不要仅仅的从字面上的意义去理解了,在看完了这篇文章之后,你就可以很自豪很有底气的对别人说,你真的会用逻辑运算符吗?

  好了,就这么两个小玩意居然背后也有着这么多的精髓,看来知识的深度是无穷的,冬季还真是一个能引发人们思考的季节。圣诞节即将到来,在这里提前预祝大家圣诞快乐,Merry Christmas!

时间: 2024-10-09 20:13:15

探寻 JavaScript 逻辑运算符(与、或)的真谛的相关文章

Javascript逻辑运算符“或”的应用

在Javascript中,逻辑运算符主要用于布尔型的逻辑运算,可以根据表达式的运算结果返回一个布尔值.由于参数并不一定非得是true或者false(它们可以蕴涵真或者假的意义),因此返回的结果也可以不是一个布尔值. 要理解这个"或"(||)运算符的作用,我们先来看一个相对简单的例子.在下面这个例子中,或运算符可以被用来为一个新定义好的变量提供一个默认值: <!-- lang: js --> var bar = false, foobar = 5, foo = bar ||

JavaScript逻辑运算符

JavaScript中有三种逻辑运算符: 非(!).与(&&).或(||) 一 :!非 !可以用来对一个值进行非运算 (一).对布尔值进行!非运算 所谓非运算就是一个布尔值进行取反操作. 1.一次运算true变false,false变true 2.如果对一个值进行两次取反,值不会变化. 对非布尔值进行取反操作,现将非布尔值变成布尔值.所以我们可以利用这个特点将其他类型的值转换成布尔值. 可以对任意一个值进行两次非运算(取反),即可将其转换为Boolean类型: 原理和使用Boolean()

javascript 逻辑运算符

<html> <head> <title></title> <script type="text/javascript"> //比较运算符 //"==="变量类型和值都相等"=="空字符串和false的意义相同 var a=false; var b=""; if(a===b){ alert("a equals b");//不弹窗 console.l

javascript逻辑运算符“||”和“&amp;&amp;”

一.先来说说||(逻辑或),从字面上来说,只有前后都是false的时候才返回false,否则返回true. alert(true||false); // truealert(false||true); // truealert(true||true); // truealert(false||false); // false 但是,从深层意义上来说的话,却有另一番天地,试下面代码 alert(0||1); 显然,我们知道,前面0意味着false,而后面1意味着true,那么上面的结果应该是tru

探寻 JavaScript 精度问题

阅读完本文可以了解到 0.1 + 0.2 为什么等于 0.30000000000000004 以及 JavaScript 中最大安全数是如何来的. 十进制小数转为二进制小数方法 拿 173.8125 举例如何将之转化为二进制小数. ①. 针对整数部分 173,采取除 2 取余,逆序排列; 173 / 2 = 86 ... 1 86 / 2 = 43 ... 0 43 / 2 = 21 ... 1 ↑ 21 / 2 = 10 ... 1 | 逆序排列 10 / 2 = 5 ... 0 | 5 /

JavaScript逻辑运算符 三元表达式

逻辑运算符: &&(与): 运算符两边只要有一个是假,那么它的运算结果就是假, 只有两个都为真的时候,运算结果才是真的. ||(或): 运算符两边只要有一个是真的那么他就是真的,只有两个 都为假的时候,它才是假的. !(非): 取反,假的变成真的,真的变成假的. 逻辑运算符需要注意: 逻辑运算符可以对任何类型的数据进行运算,但是在 运算时.可以转换为对应的布尔值. Undefine    false Null false Boolean 就是本身的值 Number 除了0以外都是true

JavaScript比较和逻辑运算符

JavaScript比较和逻辑运算符 JavaScript比较和逻辑运算符 比较和逻辑运算符用于测试true或者false. 比较运算符 比较运算符在逻辑语句中使用,以测定变量或值是否相等 例如设定x = 5: 运算符 描述 比较 返回值 == 等于 x == 8 false === 绝对等于(值和类型均相等) x === 5 true != 不等于 x != 9 true !== 不绝对等于(值和类型有一个不相等,或两个都不相等) x !== 0 true > 大于 x > 7 false

JS基础(JavaScript三大特点、基本数据类型检测、逻辑运算符的短路运算、几大循环结构的特点)

JavaScript的三大特点 1.js是单线程语言,浏览器只分配给js一个主线程,用来执行任务(函数) 2.JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型. 3.数据类型可以被忽略的语言.一个变量可以赋不同数据类型的值. JavaScript基本数据类型检测 关键字  typeof(变量名或者数据) 用来检测数据类型 typeof对于的值只有六个,分别是: string.number.boolean.object.undefined.functio

(4)javascript的运算符以及运算符的优先级

                                运算符的使用方法 在javascript的程序中要完成各种各样的运算,是离不开运算符的. 在javascript中,按运算符类型可以分为算术运算符.赋值运算符.比较运算符.逻辑运算符.条件运算符等. ( 图片来自于W3School离线手册) 算术运算符案例: <!doctype html> <head> <meta http-equiv="content-type" content="