• javascript 操作符类型隐性转换


    javascript 操作符类型隐性转换 

    (一).一元操作符
    只能操作一个值的操作符叫做一元操作符
    1.递增和递减操作符
    a. 在应用于一个包含有效数字字符的字符串时,先将其转换为数字值,再执行加减1的操作。字
    符串变量变成数值变量。
    eg: var a='1'; ++a;  //a 变成2
    b.在应用于一个不包含有效数字字符的字符串时,将变量的值设置为NaN,字符串变量变成数值变量。
    eg:var a='1aa';++a  //a 变成NaN
    c:在应用于布尔值false时,先将其转换为0再执行加减1的操作。布尔值变量变成数值变量。
    eg:var a=false;++a  //a 变成1
    d:在应用于布尔值true时,先将其转换为1再执行加减1的操作。布尔值变量变成数值变量。
    eg:var a=true;++a  //a 变成2
    e:在应用于浮点数值时,执行加减1的操作。
    eg:var a=1.1;++a  //a 变成2.1
    f:在应用于对象时,先调用对象的valueOf()方法 以取得一个可供操作的
    值。然后对该值应用前述规则。如果结果是NaN,则在调用toString()方法后再应用前述规
    则。对象变量变成数值变量。
    eg:var a=[];++a; //a变成1;内部操作原则:先把a调用valueOf()如果返回的是对象则再调用toString(),再对结果转换为

    Number按照一元操作符计算

    由此可见对于一元操作符来说都是先把变量转换为Number类型 ,再进行计算。先Number(变量),再计算。
    2. 一元加和减操作符
    在对非数值应用一元加操作符时,该操作符会像Number()转型函数一样对这个值执行转换。
    换句话说,布尔值false和true将被转换为0和1,字符串值会被按照一组特殊的规则进行解析,而对象是先调用它们的

    valueOf()和(或)toString()方法,再转换得到的值。
    下面的例子展示了对不同数据类型应用一元加操作符的结果:
    var s1 = "01";
    var s2 = "1.1";
    var s3 = "z";
    var b = false;
    var f = 1.1;
    var o = {
    valueOf: function() {
         return -1;
      }
    };
    s1 = +s1;  // 值变成数值1
    s2 = +s2;  // 值变成数值1.1
    s3 = +s3;  // 值变成NaN
    b = +b;  // 值变成数值0
    f = +f;  // 值未变,仍然是1.1
    o = +o;  // 值变成数值-1

    一元减操作符主要用于表示负数,例如将1转换成-1
    在将一元减操作符应用于数值时,该值会变成负数。而当应用于非数值时,
    一元减操作符遵循与一元加操作符相同的规则,最后再将得到的数值转换为负数,如下面的例子所示:
    var s1 = "01";
    var s2 = "1.1";
    var s3 = "z";
    var b = false;
    var f = 1.1;
    var o = {
      valueOf: function() {
        return -1;
      }
    };
    s1 = -s1; // 值变成了数值-1
    s2 = -s2; // 值变成了数值-1.1
    s3 = -s3; // 值变成了NaN
    b = -b; // 值变成了数值0
    f = -f; // 变成了-1.1
    o = -o; // 值变成了数值1
    一元加和减操作符主要用于基本的算术运算,也可以像前面示例所展示的一样用于转换数据类型。

    (二)位操作符
    ECMAScript中的所有数值都以IEEE-754 64位格式存储,但位操作符并不直接操作64位的值。而是先将64位的值转换成32位
    的整数,然后执行操作,最后再将结果转换回64位。
    对于有符号的整数,32位中的前31位用于表示整数的值(最后一位索引为0)。第32位用于表示数值的符号:0表示正数,1表示

    负数。这个表示符号的位叫做符号位,符号位的值决定了其他位数值的格式。正数以纯二进制格式存储,31位中的每一位都

    表示2的幂.没有用到的位以0 填充,即忽略不计。
    如果对非数值应用位操作符,会先使用Number()函数将该值转换为一个数值(自动完成),然后再应用位操作。得到的结果

    将是一个数值。
    在对特殊的NaN和Infinity值应用位操作时,这两个值都会被当成0来处理
    十进制转二进制算法为分步除2取余数,然后余数倒过来得到二进制结果。
    例如:

    2|__3__   1  //余数为1  
      2|_1_   1  //余数为1
         0  //余数为0

    余数倒过来为:011。即十进制3转为二进制为011
    _
    例如,数值18 的二进制表示是
    00000000000000000000000000010010,或者更简洁的10010。
    负数同样以二进制码存储,但使用的格式是二进制补码。计算一个数值的二进制补码,需要经过下列3个步骤:
    (i) 求这个数值绝对值的二进制码(例如,要求18的二进制补码,先求18的二进制码);
    (ii) 求二进制反码,即将0替换为1,将1替换为0;
    (iii) 得到的二进制反码加1。
    要根据这3个步骤求得18的二进制码,首先就要求得18的二进制码,即:
    0000 0000 0000 0000 0000 0000 0001 0010
    然后,求其二进制反码,即0和1互换:
    1111 1111 1111 1111 1111 1111 1110 1101
    最后,二进制反码加1:
    1111 1111 1111 1111 1111 1111 1110 1101
      1
    ---------------------------------------
    1111 1111 1111 1111 1111 1111 1110 1110
    这样,就求得了18的二进制表示,即11111111111111111111111111101110。要注意的是,在处理有符号整数时,是不能访

    问位31的。
    ECMAScript会尽力向我们隐藏所有这些信息。换句话说,在以二进制字符串形式输出一个负数时,
    我们看到的只是这个负数绝对值的二进制码前面加上了一个负号。如下面的例子所示:
    var num = -18;
    alert(num.toString(2)); // "-10010"
    要把数值18转换成二进制字符串时,得到的结果是"-10010"。这说明转换过程理解了二进制补码并将其以更合乎逻辑的形

    式展示了出来。
    1. 按位非(NOT)由一个波浪线(~)表示
    执行按位非的结果就是返回数值的反码
    var num1 = 25;   // 二进制00000000000000000000000000011001
    var num2 = ~num1;  // 二进制11111111111111111111111111100110
    alert(num2);  // -26
    这里,对25执行按位非操作,结果得到了26。这也验证了按位非操作的本质:操作数的负值减1。
    相当于num2 = -num1 -1
    然以上代码也能返回同样的结果,但由于按位非是在数值表示的最底层执行操作,因此速度更快。
    常见应用:

    判断字符索引 'abc'.indexOf('a') > -1  可改为~'abc'.indexOf('a')

    转整型: ~~12.123
    2. 按位与(AND)
    按位与操作符由一个和号字符(&)表示,它有两个操作符数。从本质上讲,按位与操作就是将两
    个数值的每一位对齐,然后根据下表中的规则,对相同位置上的两个数执行AND操作:
    ------------------------------------------
    第一个数值的位  第二个数值的位  结 果
    1                  1              1
    1                  0              0
    0                  1              0
    0                  0              0
    ------------------------------------------
    简而言之,按位与操作只在两个数值的对应位都是1时才返回1,任何一位是0,结果都是0。
    下面看一个对25和3执行按位与操作的例子:
    var result = 25 & 3;
    alert(result); //1
    可见,对25和3执行按位与操作的结果是1。为什么呢?请看其底层操作:
    25  = 0000 0000 0000 0000 0000 0000 0001 1001
    3  = 0000 0000 0000 0000 0000 0000 0000 0011
    ---------------------------------------------
     AND = 0000 0000 0000 0000 0000 0000 0000 0001
    原来,25和3的二进制码对应位上只有一位同时是1,而其他位的结果自然都是0,因此最终结果
    等于1。

    3. 按位或(OR)
    按位或操作符由一个竖线符号(|)表示,同样也有两个操作数。按位或操作遵循下面这个真值表
    ------------------------------------------
    第一个数值的位  第二个数值的位  结 果
    1                  1              1
    1                  0              1
    0                  1              1
    0                  0              0
    ------------------------------------------
    按位或操作在有一个位是1的情况下就返回1,而只有在两个位都是0的情况下才返回0。
    var result = 25 | 3;
    alert(result); //27
    25与3按位或的结果是27:
    25 = 0000 0000 0000 0000 0000 0000 0001 1001
    3  = 0000 0000 0000 0000 0000 0000 0000 0011
    --------------------------------------------
    OR = 0000 0000 0000 0000 0000 0000 0001 1011
    这两个数值的都包含4个1,因此可以把每个1直接放到结果中。二进制码11011等于十进制值27。
    转整型:12.123|0
    4. 按位异或(XOR)
    按位异或操作符由一个插入符号(^)表示,也有两个操作数。以下是按位异或的真值表。
    ------------------------------------------
    第一个数值的位  第二个数值的位  结 果
    1                  1              0
    1                  0              1
    0                  1              1
    0                  0              0
    ------------------------------------------
    按位异或与按位或的不同之处在于,这个操作在两个数值对应位上只有一个1时才返回1,如果对
    应的两位都是1或都是0,则返回0。
    对25和3执行按位异或操作的代码如下所示:
    var result = 25 ^ 3;
    alert(result); //26
    25与3按位异或的结果是26,其底层操作如下所示:
    25  = 0000 0000 0000 0000 0000 0000 0001 1001
    3  = 0000 0000 0000 0000 0000 0000 0000 0011
    ---------------------------------------------
    XOR = 0000 0000 0000 0000 0000 0000 0001 1010

    5. 左移
    移操作符由两个小于号(<<)表示,这个操作符会将数值的所有位向左移动指定的位数。例如,
    如果将数值2(二进制码为10)向左移动5位,结果就是64(二进制码为1000000),代码如下所示:
    var oldValue = 2;  // 等于二进制的10
    var newValue = oldValue << 5;  // 等于二进制的1000000,十进制的64
    在向左移位后,原数值的右侧多出了5个空位。左移操作会以0来填充这些空位,以便得到
    的结果是一个完整的32位二进制数
    左移不会影响操作数的符号位。换句话说,如果将2向左移动5位,结果将是64,而非64

    6. 有符号的右移
    有符号的右移操作符由两个大于号(>>)表示,这个操作符会将数值向右移动,但保留符号位(即
    正负号标记)。有符号的右移操作与左移操作恰好相反,即如果将64向右移动5位,结果将变回2:
    var oldValue = 64;  // 等于二进制的1000000
    var newValue = oldValue >> 5;  // 等于二进制的10 ,即十进制的2
    同样,在移位过程中,原数值中也会出现空位。只不过这次的空位出现在原数值的左侧、符号位的
    右侧,而此时ECMAScript会用符号位的值来填充所有空位,以便得到一个完整的值

    7. 无符号右移
    无符号右移操作符由3个大于号(>>>)表示,这个操作符会将数值的所有32位都向右移动。对正
    数来说,无符号右移的结果与有符号右移相同。仍以前面有符号右移的代码为例,如果将64无符号右
    移5位,结果仍然还是2:
    ar oldValue = 64;  // 等于二进制的1000000
    var newValue = oldValue >>> 5;  // 等于二进制的10 ,即十进制的2

    但是对负数来说,情况就不一样了。首先,无符号右移是以0来填充空位,而不是像有符号右移那
    样以符号位的值来填充空位。所以,对正数的无符号右移与有符号右移结果相同,但对负数的结果就不
    一样了。其次,无符号右移操作符会把负数的二进制码当成正数的二进制码。而且,由于负数以其绝对
    值的二进制补码形式表示,因此就会导致无符号右移后的结果非常之大,如下面的例子所示:
    var oldValue = -64;  // 等于二进制的11111111111111111111111111000000
    var newValue = oldValue >>> 5;  // 等于十进制的134217726
    这里,当对64执行无符号右移5位的操作后,得到的结果是134217726。之所以结果如此之大,
    是因为64的二进制码为11111111111111111111111111000000,而且无符号右移操作会把这个二进制码当
    成正数的二进制码,换算成十进制就是4294967232。如果把这个值右移5 位,结果就变成了
    00000111111111111111111111111110,即十进制的134217726。

    (三)布尔操作符
    布尔操作符一共有3个:非(NOT)!、与(AND)&& 和或(OR)
    1.逻辑非
    可以应用于ECMAScript中的任何值,无论这个值是什么数据类型,这个操作符都会返回一个布尔值
    逻辑非操作符首先会将它的操作数转换为一个布尔值,然后再对其求反。
    逻辑非操作符遵循下列规则:
    a.如果操作数是一个对象,返回false;  
    b.如果操作数是一个空字符串,返回true;
    c.如果操作数是一个非空字符串,返回false;
    d.如果操作数是数值0,返回true
    e.如果操作数是任意非0数值(包括Infinity),返回false;
    f.如果操作数是null、NaN、undefined,返回true;
    而同时使用两个逻辑非操作符,实际上就会模拟Boolean()转型函数的行为
    第一个逻辑非操作会基于无论什么操作数返回一个布尔值,而第二个逻辑非操作则对该布尔值求反,于是就得到了这个值真

    正对应的布尔值,最终结果与对这个值使用Boolean()函数相同

    2. 逻辑与( && )
    逻辑与操作可以应用于任何类型的操作数,而不仅仅是布尔值。在有一个操作数不是布尔值的情况下,逻辑与操作就不一定

    返回布尔值
    逻辑与操作属于短路操作,即如果第一个操作数能够决定结果,那么就不会再对第二个操作数求值。对于逻辑与操作而言,

    如果第一个操作数是false,则直接返回第一个操作数不执行第二个操作数。
    eg:  true && dd   //报错dd is not defined
         false && dd   //不会报错 ,因为false直接返回了,不会对与操作符右侧操作数求值(取值)了

    3. 逻辑或( || )
    逻辑或操作符也是短路操作符。也就是说,如果第一个操作数的求值结果为true,就不会对第二个操作数求值了
    eg: true || dd  //不会报错 ,true 直接返回了dd不会被求值

    (四). 乘性操作符
    ECMAScript定义了3个乘性操作符:乘法、除法和求模。在操作数为非数值的情况下会执行自动的类型转换
    如果参与乘性计算的某个操作数不是数值,后台会先使用Number()转型函数将其转换为数值
    Infinity 无穷,-Infinity 负无穷 。Number(Infinity) 结果还是Infinity
    a . 乘法
    i:如果乘积超过了ECMAScript数值的表示范围,则返回Infinity或-Infinity;
    ii:如果有一个操作数是NaN,则结果是NaN
    iii:如果是Infinity与0相乘,则结果是NaN;
    iv:如果是Infinity与非0数值相乘,则结果是Infinity或-Infinity,取决于有符号操作数的符号;
    v:如果是Infinity与Infinity相乘,则结果是Infinity
    vi:如果有一个操作数不是数值,则在后台调用Number()将其转换为数值,然后再应用上面的规则

    b. 除法
    i:如果操作数都是数值,执行常规的除法计算,即两个正数或两个负数相除的结果还是正数,而如果只有一个操作数有符号

    ,那么结果就是负数。如果商超过了ECMAScript数值的表示范围,则返回Infinity或-Infinity
    ii:如果有一个操作数是NaN,则结果是NaN;
    iii:如果是Infinity被Infinity除,则结果是NaN;
    iv:如果是零被零除,则结果是NaN;
    v:如果是非零的有限数被零除,则结果是Infinity或-Infinity,取决于有符号操作数的符号;
    vi:如果是Infinity被任何非零数值除,则结果是Infinity或-Infinity

    c. 求模
    求模(余数)操作符由一个百分号(%)表示
    i:如果被除数是无穷大值而除数是有限大的数值,则结果是NaN
    ii:如果被除数是有限大的数值而除数是零,则结果是NaN
    iii:如果是Infinity被Infinity除,则结果是NaN
    iv:如果被除数是有限大的数值而除数是无穷大的数值,则结果是被除数
    v:如果被除数是零,则结果是零

    (五)加性操作符
    加法和减法都属于加性操作符,与乘性操作符类似,加性操作符也会在后台转换不同的数据类型
    a. 加法
    如果两个操作符都是数值,执行常规的加法计算,然后根据下列规则返回结果
    i:如果有一个操作数是NaN,则结果是NaN;
    ii:如果是Infinity加Infinity,则结果是Infinity;
    iii:如果是-Infinity加-Infinity,则结果是-Infinity
    iv:如果是Infinity加-Infinity,则结果是NaN;
    v:如果是+0加+0,则结果是+0,如果是-0加-0,则结果是-0,如果是+0加-0,则结果是+0。
    不过,如果有一个操作数是字符串,那么就要应用如下规则
    i:如果两个操作数都是字符串,则将第二个操作数与第一个操作数拼接起来
    ii:如果只有一个操作数是字符串,则将另一个操作数转换为字符串,然后再将两个字符串拼接起来。
    如果有一个操作数是对象、数值或布尔值,则调用它们的toString()方法取得相应的字符串值,然后再应用前面关于字符串

    的规则。对于undefined和null,则分别调用String()函数并取得字符串"undefined"和"null"。
    (true + 1 ==2)
    b.减法
    与加法操作符类似,ECMAScript中的减法操作符在处理各种数据类型转换时,同样需要遵循一些特殊规则,如下所示:
    i:如果两个操作符都是数值,则执行常规的算术减法操作并返回结果;
    ii:如果有一个操作数是NaN,则结果是NaN;
    iii:如果是Infinity减Infinity,则结果是NaN;
    iv:如果是-Infinity减-Infinity,则结果是NaN;
    v:如果是Infinity减-Infinity,则结果是Infinity;
    vi:如果是-Infinity减Infinity,则结果是-Infinity
    vii:如果是+0减+0,则结果是+0;如果是+0减-0,则结果是-0;如果是-0减-0,则结果是+0
    viii:如果有一个操作数是字符串、布尔值、null或undefined,则先在后台调用Number()函数将其转换为数值,然后再根据

    前面的规则执行减法计算。如果转换的结果是NaN,则减法的结果就是NaN;
    ivv:如果有一个操作数是对象,则调用对象的valueOf()方法以取得表示该对象的数值。如果得到的值是NaN,则减法的结果

    就是NaN。如果对象没有valueOf()方法,则调用其toString()方法并将得到的字符串转换为数值。

    (六) 关系操作符
    小于(<)、大于(>)、小于等于(<=)和大于等于(>=)这几个关系操作符用于对两个值进行比较,这几个操作符都返回

    一个布尔值
    与ECMAScript中的其他操作符一样,当关系操作符的操作数使用了非数值时,也要进行数据转换或完成某些奇怪的操作。以

    下就是相应的规则。
    i.如果两个操作数都是数值,则执行数值比较。
    ii.如果两个操作数都是字符串,则比较两个字符串对应的字符编码值
    iii.如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较。
    iv.如果一个操作数是对象,则调用这个对象的valueOf()方法,用得到的结果按照前面的规则执行比较。如果对象没有

    valueOf()方法,则调用toString()方法,并用得到的结果根据前面的规则执行比较。
    v.如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较。
    eg:var result = "23" < "3"; //true
       var result = "23" < 3; //false
    字符串"23"会被转换成数值23,然后再与3进行比较,因此就会得到合理的结果。
    var result = "a" < 3; // false,因为"a"被转换成了NaN
    ( 七 ) 相等操作符
    相等和不相等——先转换再比较,全等和不全等——仅比较而不转换。
    a. 相等(==)、不相等(!=)这两个操作符都会先转换操作数(通常称为强制转型),然后再比较它们的相等性。
    在转换不同的数据类型时,相等和不相等操作符遵循下列基本规则:
    i:如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值——false转换为0,而true转换为1;
    ii:如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值;
    iii:如果一个操作数是对象,另一个操作数不是,则调用对象的valueOf()方法,用得到的基本类型值按照前面的规则进行比

    较;
    iv: null和undefined是相等的
    v:要比较相等性之前,不能将null和undefined转换成其他任何值。//undefined == 0  false;null == 0  false
    vi:如果有一个操作数是NaN,则相等操作符返回false,而不相等操作符返回true
    vii:如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回true

    ;否则,返回false。
    b.全等(===)和不全等(!==)
    在比较之前不转换操作数,不同数据类型的操作数都不全等

    (八)条件操作符
    variable = boolean_expression ? true_value : false_value;
    基于对boolean_expression求值的结果,决定给变量variable赋什么值

    (九)赋值操作符
    简单的赋值操作符由等于号(=)表示,其作用就是把右侧的值赋给左侧的变量
    如果在等于号(=)前面再添加乘性操作符、加性操作符或位操作符,就可以完成复合赋值操作
    每个主要算术操作符(以及个别的其他操作符)都有对应的复合赋值操作符
    乘/赋值(*=);
    除/赋值(/=);
    模/赋值(%=);
    加/赋值(+=);
    减/赋值(=);
    左移/赋值(<<=);
    有符号右移/赋值(>>=);
    无符号右移/赋值(>>>=)。
    计这些操作符的主要目的就是简化赋值操作。使用它们不会带来任何性能的提升

    (十)逗号操作符
    使用逗号操作符可以在一条语句中执行多个操作:
    var num1=1, num2=2, num3=3;
    逗号操作符还可以用于赋值。在用于赋值时,逗号操作符总会返回表达式中的最后一项:
    var num = (5, 1, 4, 8, 0); // num的值为0

    参考资料:javascript高级程序设计(第三版)

    关于操作符优先级:

    下表按从最高到最低的优先级列出JavaScript运算符。具有相同优先级的运算符按从左至右的顺序求值。

    运算符 描述
    . [] () 字段访问、数组下标、函数调用以及表达式分组
    ++ -- - ~ ! delete new typeof void 一元运算符、返回数据类型、对象创建、未定义值
    * / % 乘法、除法、取模
    + - + 加法、减法、字符串连接
    << >> >>> 移位
    < <= > >= instanceof 小于、小于等于、大于、大于等于、instanceof
    == != === !== 等于、不等于、严格相等、非严格相等
    & 按位与
    ^ 按位异或
    | 按位或
    && 逻辑与
    || 逻辑或
    ?: 条件
    = oP= 赋值、运算赋值
    , 多重求值

    圆括号可用来改变运算符优先级所决定的求值顺序

    参考:http://www.jb51.net/article/34922.htm

  • 相关阅读:
    阿里云ECS磁盘性能测试
    阿里云NAS性能测试
    Jumpserver堡垒机容器化部署
    k8s集群中部署RookCeph高可用集群
    使用GitHub Action进行打包并自动推送至OSS
    MYSQL ERROR 1118
    ORACLE cursor_sharing参数导致函数索引失效
    导出微信视频号的视频
    iPad作为扩展屏的几种方案
    AR VR MR XR
  • 原文地址:https://www.cnblogs.com/lmh2072005/p/3811949.html
Copyright © 2020-2023  润新知