最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 【轻聊前端】那些“无理取值”的运算

    正文概述 掘金(灵感__idea)   2021-03-14   374

    凡有数据参与且得出某种结果的,都叫运算——灵感

    本系列文章讲求循序渐进,说完变量,聊完对象,是时候讲运算了,前文说过,程序就是在做“数据存储”和“数据处理”,存储说完就是处理,运算便是处理的方式。

    四则运算(之外)

    说起运算,不得不让人联想到数学,最熟悉的就是“加、减、乘、除”四则运算,你一定能想到,JavaScript当中也有这几种运算,因为有数字类型,但它远不止这四种,而且就这四种而言,跟数学当中也不完全一样,在某些场景下,会发生“神奇的转换“。为什么?别忘了,作为计算机,对给它的任何一行代码,一个字符,都需要做出反应,特别是JavaScript这种动态弱类型语言,相当宽容,会在不知道变量是什么的情况下尽量做出反应。

    暂把“神奇的转换”留后,四则运算也不做赘述,先看四则运算之外它还有什么。

    两元运算

    什么是两元,“元”就是参与运算的数据的个数,两元即有两个数据参与运算。

    (完全)等于/不等于

    先说等于,这很简单,但新手程序员都需要一段时间适应,即JavaScript中的等于和数学中的不一样,需要用“==”符号,而不是“=”,“=”在JavaScript中代表“赋值”。

    if(a = 3){
    }
    

    这是把3赋给a,而不是判断两者是否相等,须多加注意。

    另外,数学当中只有等于、大于、小于之类,没有”不等于“,而程序里加入了“不等于”,这就可以用一个运算统一两种情况。写法如下:

    a!=b
    

    按照功能来说,这么写就够了,但并不保险,因为一个小小的是否相等,浏览器都会试图对它进行类型转换之后再比较。比如

    0 == ' '  //true  这里是空串儿,不是''
    null == undefined //true
    

    0和空格字符显然是两个概念,null 和 undefined 也不能等同。不能判定为相等,但返回是true,所以,在判断两个值是否相等时,建议使用“完全运算符”。示例如下:

    0 === ‘ ’ //false
    null === undefined //false
    

    完全运算符会在比较的同时检查类型,类型不一样就肯定不等。完全不等即“!==”。

    这样就能准确判定了。

    取模(余数)

    相比之下,取模(%)运算不是很常见,它的效果是这样的:

    let result = 55 % 10;  // 5
    

    即看两数是否能整除,如果不能,得到余数。

    应用场景有:判断是不是某个数的整数倍(本职),通过这个本职,可以判断一个数字是不是2的整数倍,进而判断“奇/偶”。

    指数

    以前,我们求一个数字的多少次方,可以用上一篇文提到的Math对象的pow方法:

    let result = Math.pow(3,2);  //9
    

    ES7之后引进了新的操作符——**,于是可以写成下面这样。

    let result = 3**2;
    

    书写上更简洁。

    赋值

    前面说了“=”是赋值,但除此之外还有一系列有关运算后赋值的简化写法。统一的表达式是:变量 运算符= 变量(常量)

    意思就是,将某变量进行运算之后再把值赋给原变量。示例如下:

    a += 1;  //等同于 a = a+1 下同
    a -= 1;
    a *= 1;
    a /= 1;
    a %= 2;
    

    逻辑操作

    什么是逻辑?在JavaScript中逻辑运算得到的结果是“真/假”、“是/否”,即判断一个条件成立与否。

    “&&”——与操作,均为真,结果才是真。

    最为直观的:

    let result = true && false;  //false
    

    但平时一般不会这么直接操作布尔值,而是使用其他运算得出的结果。比如:

    let a = 4;
    let result = a > 3 && a < 5;  // true
    

    "||"——或操作,有一个为真即为真,否则是假。

    let a = 4;
    let result1 = a < 3 || a > 5; // false
    let result2 = a > 3 || a > 5; // true
    let result3 = a > 3 || a < 5;  // true
    

    这两种运算符为日常开发的很多场景提供了便捷的判断方式,常用于流程控制中的条件判断,但有时候会被自己绕进去,比如,当需要a和b两种场景都适用时,可能会因为这个“和”字,本能地选择了“与”运算,即“&&”,这就不对了,都适用的意思是“a”或者“b”,要用“||”才对。

    另外,逻辑运算符不仅仅能用来得到“是”或“否”,还有一种常见的用法,称为“短路运算”。

    先看一段代码:

    let result;
    
    if(a){
       result = b
    } else {
       result = a
    }
    
    if(a){
        result = a;
    } else {
        result = b;
    }
    

    第一种情况,当a有值且不为false(包括隐式类型转换),result得到b,否则得到a。

    第二种情况,当a有值且不为false(包括类型转换),就不往后看了,result得到a,否则得到b。

    但上面的写法显得略繁琐,如果使用“短路运算”,可以像下面这样:

    let result = a && b;
    let result = a || b;
    

    效果是一样的。

    短路的写法为我们提供了赋值的“优先级”。逻辑运算的思路并没有改变,只是会发生赋值的动作。

    所以,当我们要在两个值之间做取舍时,就可以考虑使用“短路算法”,一行代码搞定,简洁、清晰。

    一元运算

    先说两元是因为两元大家都熟悉,易接受,一元也很好理解,一个操作符,一个操作数。

    +/-

    "+"和"-"除了作为两元操作,同样可作为一元使用,最常见的就是“正负数”。

    +1
    -1
    

    但是,如果不是直接放在数字的前面,而是变量的前面,就会有不同。

    比如:

    let a = '1'; 
    let result = +a;  // 1
    let result = -a;  //-1
    

    这段代码里,a原本是字符串的“1”,在前面加上了“+”或“-”号之后,就转变成了数字,为什么呢?因为在字符串前面加代表“正负”的符号是没有意义的,JavaScript会试图使其变得合理。

    注意两个字“试图”,说明并不总成功,如果值没法转换成数字,就会失败。

    let a = 'a';
    +a  //NaN
    

    虽然一元操作符有这么一个功能,仍属于隐式转换的范畴,只有当拿到的值和想要的值的类型不匹配的时候才需要用到,如果对自己的操作很确定,且从代码的易读性出发的话,可以直接使用Number()方法进行显式转换。

    ++/--

    说完一个的,说说两个的,两个叫“自增”或“自减”,因为没有另外的数据跟它结合,也正因为没有数据结合,每次都只能“自增”或“自减”1。

    a++  //自增1
    a--  //自减1
    

    功能简单,但放的位置就有讲究了,放前放后有区别。

    let  result = a++;   // 符号在后,先赋值后增加
    let  result = ++a;   // 符号在前,先增加后赋值
    

    这两种运算符常被用在需要重复执行的代码段,经过多次运算后达到一个临界值,再进行其他操作,或停止操作,最常见的就是for循环。

    for(let i = 0;i<=length;i++){
        //执行操作
    }
    

    每循环一圈儿,i加1,直到达到length停止。

    !

    “!”叫“取反”运算符,按说它也属于逻辑运算,是对结果的值进行取反,结果是真,取反后是假,结果是假,取反后是真。

    let a = false;
    if(!a){
        //a为假时执行的操作,假不只是false,还包括能够布尔转换为假的其他值
    }
    

    你可以在任何需要的时候使用“!”运算符,一个常用场景就是状态切换。

    let on = true;
    function changeStatus(){
        on =!on;
    }
    

    给需要切换状态的元素绑定点击事件,然后执行函数changeStatus,每点击一次,就会变为相反的值,从而达到反复点击切换状态的效果。

    三元运算

    三元运算,又叫“条件运算”。JavaScript当中三元运算符也很常见。格式如下:

    表达式?值1:值2

    示例:

    let a = 3;
    let result = a>2?'真':'假';
    

    这段代码表达的是,当a的值大于2,取前值,否则取后值。即根据表达式是否成立来决定值是什么。

    这个运算和前面聊的“||”运算的效果有相似的地方,各位可根据具体情况选择使用。

    需要注意的点

    + 的连接性

    关于“+”,我们习惯的作用是数字相加,但到了JavaScript领域,“+”还有另一个常见的作用是“连接字符串”。如下:

    let result = 'a'+'b';   // "ab"
    

    虽然字符串本身也有连接的方法,相比之下,“+”更直接和简洁。

    但如果仅此而已,就没什么可注意的,JavaScript世界最大的不确定就是“拿到的变量是什么”。

    如果是这样:

    let result = 1 + 'b';
    

    数字和字符串相加,得到的什么呢?是“1b”。

    可能你会说了,后面那个是b,没法转换成数字,才有的这个结果。那换一下:

    let result = 1 + '2';
    

    结果是“12”,显然上面的猜测并不对。

    当使用“+”号进行二元运算的时候,任何一方的数据是字符串类型,或者被转换成了字符串类型,结果都是字符串类型。比如:

    let result = "";
    result + 2  //"2"
    result + undefined  // "undefined"  
    result + null   //  "null"
    

    为什么单拎“+”号呢,因为只有“+”号有这个特殊作用,其他运算符没有。

    字符串比较

    在业务需求中,常有给一组数据按照大小排序的情况,这时候就有一个陷阱在等着我们——字符串的比较。

    字符串比较有两个算法:

    • 逐位比较,直到得出结果
    • 比较的是ASCII码值

    这样的算法就会出现如下情况:

    100 < 20   //true
    

    事实上这个结果是不对的,我故意这样写,因为有时候,用眼睛看着是数字的,其类型可能是字符串,可能比较的是“100”和“20”,就会出现上面的情况。

    用 charCodeAt() 方法可以查看字符的ASCII码值,'1'是49,而'2'是50。比较完第一位就已经分出大小了。

    再看个例子:

    '13' > '123'   //true
    

    首位1是相等的,第二位3的ASCII码比2的ASCII码大,出结果。

    所以,在进行数据排序的时候,一定要注意类型,否则可能和预期不一致,数字如此,字母或其他特殊符号也是一样,不再赘述。

    对象的隐式转换

    面试题放送时间到~

    问“什么情况下,a == 1 && a == 2 && a == 3 是成立的?“

    这...看起来很不合常理,不是故意刁难吗?

    先别急,我们讲一下上面一直没提过的东西。上面一直在说基本类型会转换,而没说对象。

    拿值和对象作比较看似没有实用的地方,但程序依然允许运行,且会有相应的处理机制。

    对象到数字(number)和字符串(string)类型值的转换,是直接与valueOf()以及toString()方法相关的。规则如下:

    • 如果试图转换为字符串,则先尝试toString()方法,然后再尝试valueOf()方法。

    • 否则,先尝试调用valueOf()方法,再尝试调用toString()。

    有人要问了,这俩方法哪来的?还记得上篇文章的内容吗?它们是来自原型的内置方法。

    于是,上面的题目便找到了使其成立的途径:

    let a = {
      i: 1,
      valueOf: function () {
        return a.i++;
      }
    }
    
    if(a == 1 && a == 2 && a == 3) {
      console.log('我成真了!');
    }
    
    // 我成真了!
    

    可以利用类型转换时会调用valueOf(也可以是toString)方法的特性,在里面写我们想要的其他效果,就可以了。

    明白了这个道理,是不是一点都不怕了?

    当然,这道题不仅这一种方案,只是另一种方案稍微偏离主题,我们后面聊到对象的时候再深挖~

    总结

    JavaScript中的运算,说多不多,说少也不少,特别是隐式类型转换的处理机制,需要较多经验的积累,大坑没有,小坑不断。

    鉴于篇幅原因,这里把不常用的和一些细节略了,但不管哪种情况,可概括为两条:

    • 取值:不论数学计算,字符串连接,甚至“短路算法”,目的都是获取一个值,当无法得到合法值时,就会返回NaN或者报错之类期望之外的结果。
    • 逻辑判断:使用“&&、||、!”或者隐式转换的情况,作为流程控制的条件判断。

    这样以来,我们就只需要关心自己要做什么,每碰到一种意外情况就记下,慢慢就都清楚了。

    说完变量(值的存储)、对象系统(编程的土壤)、运算(数据处理的方式)之后,接下来就是对不同的类型进行各个击破了。

    下篇见~

    博文链接:【轻聊前端】那些“无理取值”的运算

    系列文章:

    【轻聊前端】打好基本功,跟我轻松学原生

    【轻聊前端】小角色,大用途——变量

    【轻聊前端】为什么说一切皆对象?


    起源地下载网 » 【轻聊前端】那些“无理取值”的运算

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元