深入了解JavaScript的逻辑运算符(与、或)
十二月已经过半,冬季是一个美妙的季节,寒冷的空气逼得人们不得不躲在安逸舒适的环境里生活。冬季会给人一种安静祥和的氛围,让人沉浸在其中,仿佛是一个旧的阶段的结束,同时也是一个新的阶段的开始。这么说来,西方和中国的圣诞节和春节都选择在了冬季也不是没有道理,在一年中最寒冷的时候,人们拥簇在温暖的环境里,彼此诉说着过去一年里自己的成就,展望着新的一年里美好的愿望,相互挂念的人团聚,天气的寒冷和人情的温暖形成了强烈的对比。而在天寒地冻之中,仿佛更有利于人们思考,去探寻知识的真谛。
这次想分享的是JS当中的逻辑运算符与、或,也就是&&、||,初来乍到的同学们看到这里就会觉得没趣了,这玩意有什么好分享的,刚开始学JS的时候不就会了吗,我用了无数遍都没有什么问题啊。而有经验的同学可能会陷入沉思,难不成这其中会有什么奥秘所在?没错,别看这简简单单的几个运算符,虽然这是最基础的知识,但其中隐藏的奥秘却十分耐人寻味,接下来我就为大家一一揭开这简答的运算符背后的奇妙之处。
基础的作用我就不说了,这两个符号是个程序员都能明白,这里首先我想先来说一说JS当中的隐式转换。
众所周知,JS在做逻辑判断的时候会自动将非布尔类型的值进行隐式转换,转换成布尔类型的值然后在进行逻辑运算。在初学JS的时候,都会讲到在隐式转换中,除了几个特定的假值,其他的均会转换成真值,这些假值有:
NaN; ""; undefined; null; 0;
有了这些隐式转换的规则,便构成了JS当中逻辑运算的核心基础。
其实在JS当中,要说“逻辑运算符”其实并不完全正确,KyleSimpson在《YouDon'tKnowJS》系列书当中提到:“与其说是‘逻辑运算符',不如说是‘选择器运算符'。”为什么大师要这样说呢?其实我们大多数人都被JS的表象给蒙蔽了,比如下面一段非常简单的代码:
if("hello"&&0){ console.log(true); }else{ console.log(false); }
如果你对JS了解的不够深刻,你可能会这样解释这段代码:首先在逻辑判断中,"hello"是一个真值,0是一个假值,一个真值和一个假值进行与运算,结果为false。这也可能是大多数人的理解,但其实不然,其内部的原理可不止这么简单,因为&&和||返回的并不是判断条件的真假,而是判断条件中的一个原始值。它将依次对条件判断中的值进行判断,如果是非布尔值,则转换成布尔值做判断,然后再根据判断条件来决定返回哪一个值。
对于&&:该运算符返回条件语句中的第一个假值,如果所有的值都为真,则返回最后一个值,&&也被称为“守护运算符”。比如下面一段代码:
vara="hello"&&"world"; console.log(a);//world varb=0&&1; console.log(b);//0
可以看出,逻辑运算符其实返回的并不是条件的真假,而是原始值。如果条件语句中有多个&&运算符,则一样遵循以上原则,从左向右依次判断,如果遇到了假值,就返回该假值,如果所有值都为真,则返回最后一个值。
对于||:该运算符与&&运算符相反,它返回条件语句中的第一个真值,如果所有值都为假,则返回最后一个值。比如下面一段代码:
vara="hello"||0; console.log(a);//hello varb=0||NaN; console.log(b);//NaN
同样,||返回的也不是布尔值。如果有多个||则同样遵循相同的原则,从左向右依次扫描。
讲到这里也就来到了本篇文章的核心,在JS当中,条件判断语句都是建立在隐式转换之上的,也就是说所谓的逻辑运算符,实际上是在条件判断语句中从左向右依次扫描,如果是一个布尔值,则判断该布尔值的真假,如果是一个非布尔值,则先对该值进行隐式转换,然后再判断真假,如果满足条件,则返回该值,如果没有满足条件值,则返回最后一个值,然后在对返回的这个值做判断,如果是一个布尔值,则直接判断,如果是一个非布尔值,则先隐式转换成布尔值,再做判断。所以我们也可以把&&称为“取假运算符”,把||称为“取真运算符”,因为这两个运算符的实质都是取条件语句中的第一个真值或者假值,如果始终没有找到,则返回最后一个值。而这样的算法也恰好满足逻辑判断的需求,比如&&运算符,如果所有的值都是真值,那么返回哪个值其实都无所谓,因为所有值都能够被隐式转化为true,而只要有一个假值,则判断条件不成立,所以会返回第一个遇到的假值。而||运算符,如果所有的值都是假值,返回任意一个都会被隐式转换成false,但只要遇到了一个真值,则判断条件成立,所以会返回第一个遇到的真值。&&和||运算符都是“短路”的。
所以我们可以自己实现一个逻辑运算的函数:
//&&等价于: functionAND(){ for(vari=0;i<arguments.length;i++){ if(!arguments[i]){ returnarguments[i]; } } returnarguments[i-1]; }
//||等价于: functionOR(){ for(vari=0;i<arguments.length;i++){ if(arguments[i]){ returnarguments[i]; } } returnarguments[i-1]; }
(注:在这里我同时也想对!这个运算符做讲解,但考虑到内容和篇幅的问题,暂时不做深入探究,仅做简单讲述。!运算符实际上运行机制与&&和||是一样的,首先会对参数值做判断,如果是一个布尔值,则进行取反运算,如果是一个非布尔值,则先进行隐式转换,再进行取反运算。而我们通常写的if(something)语句,实际上的意思if(!!something))
然后我们可以这样使用:
vara=["hello",undefined,"world"]; console.log(AND.apply(null,a));//undefined varb=["",0,NaN]; console.log(OR.apply(null,b));//NaN
进而,我们就可以推断出一下结论:
a=x||y; //等价于: a=x?x:y; a=x&&y; //等价于: a=x?y:x;
这通常也是一些压缩工具所做的事情,它们尽可能的将繁杂的条件判断语句转换成&&或者||,因为这样代码更加的精简,但是可读性则就不那么可观了。
对于最开始的那一段代码:
if("hello"&&0){ console.log(true); }else{ console.log(false); }
我们现在就要这样解释:首先这是个与运算符,与运算符的作用是取第一个假值,如果所有的值都为真,那么则返回最后一个值。所以在这条语句中,第一个值是"hello",因为该值是一个非布尔值,JS引擎会先将它隐式转换成布尔值,而该值不在假值的范围内,所以会被转化成true。随后JS引擎会继续查找,第二个值是0,该值同样也不是一个布尔值,所以JS引擎也会先将它隐式转换成布尔值,而该值在假值的范围内,所以会被转化成false,满足&&运算符的查找条件,则将值0返回。而条件判断语句接受到了值0,该值不是一个布尔类型的值,所以会先对它进行隐式转换,而该值在假值范围内,所以会被转化成false,然后控制台会输出false。
所以说以后当我们看到&&和||时候,就不要仅仅的从字面上的意义去理解了,在看完了这篇文章之后,你就可以很自豪很有底气的对别人说,你真的会用逻辑运算符吗?
好了,就这么两个小玩意居然背后也有着这么多的精髓,看来知识的深度是无穷的,冬季还真是一个能引发人们思考的季节。圣诞节即将到来,在这里提前预祝大家圣诞快乐,MerryChristmas!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持毛票票!