运算符对于大家来说并不陌生,只要平时写代码就会频繁用的到。可能平时大家只关注它们的使用层还停留在只知其用法的表面,但是运算符有一些鲜为人知技能,明白以后会让你掌握运算符的原理和运算符的奇技淫巧以及解决一些面试题
先来看一些面试题,请小伙伴本着不去试的原则写出下而四道题的运行结果
//1
console.log('kaivon' && (2+1));
console.log(![] || '你好,siri');
//2
{
let a=10,b=20;
const fn=()=>(a++,b++,10);
console.log(a,b,fn());
let c=fn();
console.log(a,b,c);
}
//3
for(var i=0,j=0,k;i<6,j<10;i++,j++){
k=i+j;
}
console.log(k);
//4
{
let a=1;
let b=a++;
console.log(a,b);
let c=1;
let d=++c;
console.log(c,d);
}
对于面试题,我一开始是拒绝的,内心是崩溃的。总是会想这些题没有意义啊,真正在开发的时候谁会去做题呀,更不会遇到这么无聊的东西,为什么会用这种东西来面试?难道说面试官是过来装逼的么?看到我们回答不上来,一脸不屑地鄙视我们么?反过来想想,面试官跟我们无冤无仇,前端何苦为难前端?然而这些东西其实是有意义的,从你对这些题的回答可以看出你的基础知识全面性,并且能判断出你的技术能力。
以上面试题包含三种运算符,逻辑运算符、逗号运算符、递增递减运算符,我就分别来介绍这三种运算符
逻辑运算符
且运算符:&&
- 并且的意思,至少需要两个数据(也可以为表达式)符号左右各一个。并且会把两边的结果转成布尔值
- 如果左侧的值为真,返回右侧的值。如果左侧的值为假,返回左侧的值(不会计算右边的结果)
- 只有当左右两边的结果都为真的时候,整个结果才为真(用于判断)
- 且运算符可以出现多个,会依次按从左到右的顺序,遇到假的结果便返回。如果都为真则返回最后一个结果
console.log('kaivon' && (2+1)); //3
遇到&&
运算符,先去计算左边的结果并转成布尔值,左边为字符串kaivon
,它转为布尔值的结果为true
,所以会返回&&
运算符右侧的结果。右侧为一个表达式,计算后的结果为3,所以整个结果为3
console.log(![] && '你好,siri'); //false
左侧的表达式是把一个空数组转成布尔值(对象转基本数据类型的算法私信我要视频)并取反的结果。空数组转成布尔值结果为true
,取反后结果为false
。当左侧的结果为false
时会直接返回,并不会去理会右侧的内容,所以直接返回左侧的结果false
let n=1;
n-1 && (n+=5);
console.log(n); //1 左侧为假,所以不会执行右侧的结果,n不会加5
const fn=()=>console.log('函数被调用了');
n==1 && fn();
第一个console.log
的结果为1,说明n+=5
这个表达式并没有执行。因为&&
运算符左边的表达式运算结果为0转成布尔值为false
,所以直接返回左边的结果,不会去管右边的表达式,所以n的值并不会变。
第二个console.log
会打印出内容,说明&&
运算符的右侧表达式被执行了,因为n的值并没有改变还是1,所以左边的表达式运行结果为true
,根据规则会返回右侧的结果,所以执行调用函数fn
console.log(true && 'kaivon' && (2-2) && 4 && '陈学辉' && true); //0 返回2-2的结果
console.log(true && 'kaivon' && [] && 4 && '陈学辉'); //陈学辉
根据上面最后一条规则可以很轻易得出上面的运算结果。运算会按从左到右的顺序执行,一旦遇到表达式的结果为false
的话就会停止执行,并且整个表达式会返回这个运算结果。如果所有表达式的结果都为true
,那整个结果为最后那个表达式的结果
或运算符:||
- 或者的意思,至少需要两个数据(也可以为表达式)符号左右各一个。并且会把两边的结果转成布尔值
- 如果左侧的值为真,返回左侧的值(不会计算右边的结果)。如果左侧的值为假,返回右侧的值
- 如果有一边的结果为真的话,整个结果就为真(用于判断)
- 或运算符可以出现多个,会依次按从左到右的顺序,遇到真的结果便返回。如果都为假则返回最后一个结果
let n=1;
n-1 || (n+=5);
console.log(n); //6
||
运算符左边表达运算结果为0转布尔值为false
,根据上面列出的规则会返回右侧表达式执行的结果,所以会执行n+=5
,最终n的结果为6
console.log(false || '' || (2-2) || 4 || '陈学辉' || true); //4
console.log(false || '' || ![] || 0 || undefined); //undefined
根据上面的规则也很容易知道运行结果,||
运算符的左侧 运行结果为false
的话就会执行右侧的表达式,直到遇到计算结果为true
的表达式才会停下来,并返回这个值。如果所有表达式都没有返回true
,则取最后表达式的结果
或运算符的用途:
function fn(text){
text=text || 'kaivon'; //用户给了参数,取用户给的值;用户没有给参数,取默认值
console.log(text);
}
fn(); //kaivon 用户没有传参数,就会用默认的'kaivon'
fn('陈学辉'); //陈学辉 用户有传参数,就会用传的参数
上面代码的这种形式是ES5写面向对象的主要形式,用于对参数进行处理。如果用户传了参数,那会取用户所传的参数;如果用户没有传参,那取默认的参数。保证函数始终有参数,不会报错
逗号运算符
- 将多个表达式放在一条语句里,按从左到右的顺序执行每个表达式,返回最后那个表达式的结果(在一条语句里执行多个运算)
- 优先级最低,最后才会运算逗号
- 逗号运算符的两边不能是语句(赋值语句)
console.log(1,2,3); //1 2 3
console.log((1,2,3)); //3
console.log
是个函数,它里面的逗号表示参数分隔的意思,并不是逗号操作符。要变成操作符的话,就加个括号,加个括号后就变成了表达式,而表达式必需要求出一个值,所以里面的逗号就变成了操作符
let a=10,b=(a++,20,30);
console.log(a,b); //11 30
第一行代码中的第一个逗号的作用是:可以在一行中声明多个变量,减少let
关键字。从第二个开始被放到了括号里,而加了括号后就是个表达式。还是那句话,表达式一定会产生一个值,这个时候逗号就是个运算符了,会把最后一个赋给变量,也就是30。
下面来详细分析一道面试题,再深度的理解一下逗号运算符
for(var i=0,j=0,k;i<6,j<10;i++,j++){
k=i+j;
}
console.log(k); //18
很多小伙伴会说这个k的值不应该是14么?i的值走到5不就停了,j的值走到9不也停了,那加起来应该是14啊!为什么是18,这不科学啊!!!
要明白这个原因需要结合for循环的三条语句以及逗号运算符的作用去才能理解
说明:
- for循环的第一个语句
var i=0,j=0,k
是初始化一些变量,这里的逗号与上个代码块第一条语句的逗号一样,作用为在一行里声明多个变量- for循环的第二个语句
i<6,j<10
作用为取一个循环范围,这里要注意循环范围只能有一个条件,不能说既小于5又小于8,所以这里的逗号就是真正的逗号运算符,它只能取一个值,取的就是最后那个j<10
- for循环的第三个语句
i++,j++
,这条语句的逗号还是个运算符,表示在一行里执行多条语句,但是这个语句不需要有返回值,只用把语句执行了就行- 综上所述,这个
for
循环表示:声明三个变量,条件范围为j<10
,同时i与j每走一次都要加一次。当j的值为9的时候就不再加了,此时i的值也一样会加到9它已经没有范围限制了会无限的加,但是j有范围并不会无限加。所以i的值是跟着j在走,得出结果i+j=18
逗号运算符的另一个作用:交换两个变量的值
声明两个变量,要求通过某种方式让两个变量的值进行交换,你会用什么方法?
let a=10;
let b=20;
//问:如何让a与b的值进行交换
有一种笨方法是利用一个中间变量可以完成,代码如下:
let a=10;
let b=20;
let c;
c=a;
a=b;
b=c;
console.log(a,b); //20 10
利用逗号运算符,代码如下:
let a=10;
let b=20;
a=[b][b=a,0];
console.log(a,b); //20 10
可以看到利用逗号运算符倒是很容易实现需求,但是代码阅读起来好像很费劲,分析如下:
a=[b][b=a,0]; //这条代码的两个中括号表示,前面为数组,后面为下标。在数组中取某一个数据并赋值给a
a=[20][b=10,0] //分别把a与b的值套进去,注意第二个中括号里的b=a,这么写是把a的值赋给b,所以只能套a的值
/*
* 重点看第二个中括号里的代码,此时这个中括号的作用为下标,所以里面必需产生一个值,那里面的逗号就是运算符了
* 根据逗号运算符的作用,先执行两个表达式,把b的值改成10,再返回最后表达式的值0
* 所以这个中括号牛比的地方有两个,第一个是把b的值改成了10,第二个是整体返回0。也就变成了下面
*/
a=[20][0] //这不表示把第0个数据的值(20)赋给a
所以,逗号运算符用巧了就是巧他妈给巧开门,巧到家了~
递增递减运算符
- 它俩可以放在操作数的前面,也可以放在操作数的后面
- 不管它俩放在哪个位置,都是一个表达式,表达式的话肯定返回一个值
- 它俩具有隐式类型转数字的作用
首先验证表达有值,不管放前面还是放后面都会有值
let a=3;
console.log(a++); //3
console.log(++a); //5
后自增、后自减
- 表达式结果为数据直接转数字后的值
- 数据结果为加1或者减1的值
let a=['20'];
console.log(a++); //20 表达式结果为a转数字后的值
console.log(a); //21 数据本身变成了+1后的值
let b='20';
console.log(b--); //20 表达式结果为b转数字后的值
console.log(b); //19 数据本身变成了-1后的值
前自增、前自减
- 表达式与数据的结果一样,都为数据加1或者减1的值
let a=['20'];
console.log(++a); //21 表达式结果为a转数字后并加1的值
console.log(a); //21 数据本身也为a转数字后并加1的值
let b='20';
console.log(--b); //19 表达式结果为a转数字后并减1的值
console.log(b); //19 数据本身也为a转数字后并减1的值
两种写法对比
- 两种写法的区别在于表达式的结果不同。数据的结果写前面与写后面都一样
- 如果要用表达式的结果,看谁在前面
- 数据在前面,结果为数据的值
- 符号在前面,结果为数据+1或者数据-1的值
{
let a=1;
let b=a++;
console.log(a,b); //2 1
}
{
let a=1;
let b=++a;
console.log(a,b); //2 2
}
通过对比,a的值不管是在前面++还是在后面++,结果都为2(a+1的值)。但b的值(表达式的值)可以看谁在前面,a在前面那就取a的值,++在前面那就取a+1的值
善于总结!善于总结!善于总结!重要的提醒打三遍!