JavaScript中“&&”和“||”操作符的意义,深入理解和使用场景
一、概念
与其他语言不同,在js中,逻辑运算符可以返回任何类型的数据,不仅仅是true和false。
&&和||的返回值是两个操作数的其中一个。即a&&b或者a||b返回的是要么是a,要么是b,而其他语言中返回的是true or false。
在js逻辑运算中,需要隐式的转换为boolean类型再来运算,转换规则为:
1. 对象、非零number、非空string——>true
2. 0、""、null、false、undefined、NaN——>false
具体见下表:
| 
 数据类型  | 
转换为boolean后的值 | 
| NAN | FALSE | 
| null | FALSE | 
| undefined | FALSE | 
| Object | TRUE | 
| Function | TRUE | 
| 0 | FALSE | 
| 非零的数字 | TRUE | 
| ""(空字符串) | FALSE | 
| 非空字符串 | TRUE | 
因此:
a && b : 将a, b转换为Boolean类型, 再执行逻辑与, 如果结果是true返回b, false返回a
a || b : 将a, b转换为Boolean类型, 再执行逻辑或, 如果结果是false返回b, true返回第一个为true的值。
逻辑&&和逻辑||还有一个短路原则:知道了前面第一个的结果就知道最后的输出
a&&b:左操作数为假值时,返回左操作数,否则返回右操作数。
a||b:左操作数为假值时,返回右操作数,否则返回左操作数。
只要“||”前面为false,不管“||”后面是true还是false,都返回“||”后面的值。
只要“||”前面为true,不管“||”后面是true还是false,都返回“||”前面的值。
只要“&&”前面是false,无论“&&”后面是true还是false,结果都将返“&&”前面的值;
只要“&&”前面是true,无论“&&”后面是true还是false,结果都将返“&&”后面的值;
同样对于多个操作数的情况:
a||b||c||d:若结果为true则返回第一个true值,若结果为false则返回最后一个操作数。eg:var a = “” || null || 3 || 2 -> var a = fasel || false || true || true 结果为true 则返回第一个true,即是3
a&&b&&c&&d:若结果为false则返回第一个false,若结果为true则返回最后一个操作数。eg:var b = 2&&null&&1&&0 -> var b = true&&false&&true&&false结果是false 则返回第一个false 即是null
二、理解
“&&”和“||”运算符均可以从三个不同的层次来逐步理解:
以“&&”为例解释如下:
(1)最简单的第一层理解是,当操作数都是布尔值的时候,“&&”对两个值执行布尔与(AND)操作,只有在第一个操作数和第二个操作数都是true的时候,它才返回true。如果其中一个操作数是false,它返回false。
(2)“&&”的操作数并不一定是布尔值。于是对“&&”的第二层理解是,“&&”可以对真值和假值进行布尔与(AND)操作。如果两个操作数都是真值,那么返回一个真值;否则,至少一个操作数是假值的话,则返回一个假值。在JavaScript中任何希望使用布尔值的地方,表达式和语句都会将其当做真值或假值来对待,因此实际上“&&”并不总是返回true和false。
(3)第三层理解,运算符首先计算左操作数的值,即首先计算“&&”左侧的表达式。如果计算结果是假值,那么整个表达式的结果一定也是假值,因此“&&”这时简单地返回左操作数的值,而并不会对右操作数进行计算。反过来讲,如果左操作数是真值,那么整个表达式的结果则依赖于右操作数的值。如果右操作数是真值,那么整个表达式的值一定是真值;如果右操作数是假值,那么整个表达式的值一定是假值。
理解如下例子对于理解“&&”可能不会去计算右操作数的情况至关重要,在以下示例代码中,变量p的值是null,而如果计算表达式p.x的话则会抛出一个类型错误异常。但是示例代码使用了“&&”的一种符合语言习惯的用法,因此只有在p为真值(不能是null或者undefined)的情况下才会计算p.x。反过来,我们一般需要用某个对象p中的某个元素时,为了严谨也应该先对其是否存在进行判断。
var o = { x : 1 };
var p = null;
o && o.x // =>1:o 是真值,因此返回值为o.x
p && p.x //=>null: p是假值,因此将其返回,而并不去计算p.x
三、使用场景
1.||运算符最常用的方式是用来从一组备选表达式中选出第一个真值表达式,即从一系列值中获取第一个true值。
// 如果max_width已经定义了,直接使用它;否则在preferences对象中查找max_width;如果没有定义它,则使用一个写死的常量
var max = max_width || preferences.max_width || 500;
2.判断某个元素是否存在时:if(attr)写成if(!!attr)更加严谨。
!!的作用是把一个其他类型的变量转成的bool类型。eg:
typeof 5//"number"
typeof !!5//"boolean"
3.对函数中的参数赋以默认值:a=a||"defaultValue"; 
例如当a不存在或不合法时为其赋默认值,比起如下两种写法:
if(!a){
  a="defaultValue";
} 
if(a==null||a==""||a==undefined){
  a="defaultValue";
}
用||一句话就可以实现,简单又优雅:
a=a||"defaultValue";
4.利用&&的短路特性有条件的执行代码
(1)在回调中,经常这样写:callback&&callback(),先判断 callback 是不是存在,存在才执行,这样写更加严谨,如果直接写 callback(); 当callback不存在时代码就会报错。
(2)又或者常见的条件语句:if (a==b) stop();如果用&&来实现即为:(a==b)&&stop(); 
(3)判断某个对象存在再取值:p && p.x
应用举例:
如图: 
假设对成长速度显示规定如下: 
成长速度为5显示1个箭头; 
成长速度为10显示2个箭头; 
成长速度为12显示3个箭头; 
成长速度为15显示4个箭头; 
其他都显示都显示0个箭头。
(1)最容易想到也最常规的方法:if-else
var add_level = 0;
if(add_step == 5){
add_level = 1;
}
else if(add_step == 10){
add_level = 2;
}
else if(add_step == 12){
add_level = 3;
}
else if(add_step == 15){
add_level = 4;
}
else {
add_level = 0;
}
(2)switch方法:
var add_level = 0;
switch(add_step){
case 5 : add_level = 1;
break;
case 10 : add_level = 2;
break;
case 12 : add_level = 3;
break;
case 15 : add_level = 4;
break;
default : add_level = 0;
break;
}
(3)而如果用&&和||就会超级简单:
var add_level = (add_step==5 && 1) || (add_step==10 && 2) || (add_step==12 && 3) || (add_step==15 && 4) || 0;
优化为:
var add_level={'5':1,'10':2,'12':3,'15':4}[add_step] || 0; //对象取值有两种方式,一种object.key,一种是object[key],此处为法二
特别是如果需求改成: 
成长速度为>12显示4个箭头; 
成长速度为>10显示3个箭头; 
成长速度为>5显示2个箭头; 
成长速度为>0显示1个箭头; 
成长速度为<=0显示0个箭头。 
那么用switch实现起来也很麻烦了,而同样用&&和||只要如下即可。
var add_level = (add_step>12 && 4) || (add_step>10 && 3) || (add_step>5 && 2) || (add_step>0 && 1) || 0;
注:与&&和||不同,!操作符的行为与C、Java等语言是一致的,只返回boolean值(true或false)。
参考:
http://www.cnblogs.com/yanayana/p/7079345.html
全面解析JavaScript中“&&”和“||”操作符(总结篇)
JavaScript中“&&”和“||”操作符的意义,深入理解和使用场景的更多相关文章
- 全面解析JavaScript中“&&”和“||”操作符(总结篇)
		
1.||(逻辑或), 从字面上来说,只有前后都是false的时候才返回false,否则返回true. ? 1 2 3 4 alert(true||false); // true alert(false ...
 - javascript中的操作符详解1
		
好久没有写点什么了,根据博主的技术,仍然写一点javascript新手入门文章,接下来我们一起来探讨javascript的操作符. 一.前言 javascript中有许多操作符,但是许多初学者并不理解 ...
 - JavaScript中in操作符(for..in)、Object.keys()和Object.getOwnPropertyNames()的区别
		
ECMAScript将对象的属性分为两种:数据属性和访问器属性.每一种属性内部都有一些特性,这里我们只关注对象属性的[[Enumerable]]特征,它表示是否通过 for-in 循环返回属性,也可以 ...
 - [转] JavaScript中in操作符(for..in)、Object.keys()和Object.getOwnPropertyNames()的区别
		
ECMAScript将对象的属性分为两种:数据属性和访问器属性.每一种属性内部都有一些特性,这里我们只关注对象属性的[[Enumerable]]特征,它表示是否通过 for-in 循环返回属性,也可以 ...
 - Javascript中void操作符
		
Javascript中void是一个操作符,该操作符指定要计算一个表达式但是不返回值. void操作符用法格式如下:1.javascript:void (expression)2.javascript ...
 - JavaScript中对null和undefined的理解
		
前沿: 今天工作中遇到了监视一个变量是undefined,结果判断写的是==null 返回值是true,这个结果引起了我对这两个东西的兴趣. 查询了相关的文章理解并测试了.发现有以下特点: 1.广义上 ...
 - JSON 在JavaScript 中的应用及自己的理解
		
[对象和json]JSON:JavaScript 对象表示法(JavaScript Object Notation).JSON 是存储和交换文本信息的语法.类似 XML.JSON是一种数据格式,不是一 ...
 - javascript中new操作符的原理
		
javascript中的new是一个语法糖,对于学过c++,java 和c#等面向对象语言的人来说,以为js里面是有类和对象的区别的,实现上js并没有类,一切皆对象,比java还来的彻底 new的过程 ...
 - javascript中的prototype和__proto__的理解
		
在工作中有时候会看到prototype和__proto__这两个属性,对这两个属性我一直比较蒙圈,但是我通过查阅相关资料,决定做一下总结加深自己的理解,写得不对的地方还请各位大神指出. 跟__prot ...
 
随机推荐
- 【LG2257】YY的GCD
			
[LG2257]YY的GCD 题面 洛谷 题解 题目大意: 给定\(n,m\)求\(\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)为质数]\). 我们设\(f(x)=[x为 ...
 - GitHub中webhooks的使用
			
目录 GitHub中的webhooks的配置 对配置的webhooks的进行测试 目前在团队在设计一个应用管理的功能,需要了解到常用代码托管的Webhooks的使用.GitHub中的webhooks首 ...
 - python登录验证码生成及自动化测试规避
			
在用django写论坛的时候,需要有登录及注册功能. 故就登录界面后端需要生成随机验证码并传值给前端的代码进行编写如下. 验证码生成png需要调用到python的图形库 生成注册码img import ...
 - selenium +java 多个类公用driver问题
			
问题点:太久没有写selenium代码,居然把driver公用的问题忘记了,即:每写一个测试类,执行过程中都会新建一个窗口,这样应该说是非常不专业的. 大概想了一个方法,虽然看起来也不怎么专业,但感觉 ...
 - Centos6升级至openssh-7.5p1
			
最近公司有几台服务器需要搬至甲方(政府单位),所以在安装服务时用的是16年的openssh7.3pl, 今天通知我们有漏洞,需要再一次升级,看到官方文档上版本已升级至7.5,所以干脆直接搞7.5 具体 ...
 - 音频分析框架pyAudioAnalysis文档
			
“ pyAudioAnalysis是一个非常好用且强大的音频分析开源工具,能实现音频的特征提取.分类和回归模型的训练和执行,以及其他一些实用的功能.此外,本文档并非直译,也有部分比较简略,可以结合源码 ...
 - vs2017 asp.net FriendlyUrls 新特性
			
这个包如何使用呢?其实很简单,只需将nuget包添加到项目中,再调用routes.EnableFriendlyUrls(),你就可以通过/Foo来访问/Foo.aspx了!你也能够利用URL片段将更多 ...
 - 【探路者】团队互评Alpha版本
			
[探路者]组互评连接: 1互评作品:SkyHunter http://www.cnblogs.com/zej87/p/7802000.html 2互评作品:爱阅app http://www.cnblo ...
 - 团队开发--NABCD
			
团队成员介绍: 李青:绝对的技术控,团队中扮演“猪”的角色,勤干肯干,是整个团队的主心骨,课上紧跟老师的步伐,下课谨遵老师的指令,课堂效率高,他的编程格言“没有编不出来的程序,只有解决不了的bug”. ...
 - C# 未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”提供程序。
			
在菜单 “项目”的最下面 工程属性 菜单,选择“生成”选项卡,将目标平台由“Amy CPU”或者“*64”改成“*86”.