你不知道的类型转换

前言

相信咱们在工做中常常会遇到类型转换的需求。可是类型转换也分为隐式强制类型转换”(implicit coercion)和“显式强制类型转换”(explicit coercion)。 例如:javascript

var a = 42;
var b = a + ""; // 隐式强制类型转换 
var c = String( a ); // 显式强制类型转换
复制代码

显式强制类型转换明确告诉咱们哪里发生了类型转换,有助于提升代码可读性和可维 护性。 隐式强制类型转换则没有那么明显,是其余操做的反作用。尤为是 == 时,有时候咱们就会迷糊,不知道过程当中发生了什么,感受上好像是显式强制类型转 换的反面,实际上隐式强制类型转换也有助于提升代码的可读性,今天咱们就来说一讲两种强制类型转换.java

显式强制类型转换

显式强制类型转换是那些显而易见的类型转换,旨在让代码更加清晰易读数组

字符串和数字之间的显式转换

var a = 42;
     var b = String( a );
     var e = a.toString();
     var c = "3.14";
     var d = Number( c );
     var f = +c;
     b; // "42"
     e; // ''42
     d; // 3.14
     f; //3.14
复制代码

toString()其中涉及隐式转换。由于 toString() 对 42 这样的基本类型值不适用,因此 JavaScript 引擎会自动为 42 建立一个封 装对象,而后对该对象调用 toString().ui

一元运算 + 被广泛认为是显式强制类型转换spa

显式解析数字字符串

解析字符串中的数字和将字符串强制类型转换为数字的返回结果都是数字。但解析和转换 二者之间仍是有明显的差异.解析容许字符串中含有非数字字符,解析按从左到右的顺序,若是遇到非数字字符就停 止。而转换不容许出现非数字字符,不然会失败并返回 NaNprototype

var a = "42";
    var b = "42px";
    Number( a );    // 42
    parseInt( a );  // 42
    Number( b );    // NaN
    parseInt( b );  // 42
复制代码

显式转换为布尔值

咱们可使用Boolean(..) 和!!,可是!!是咱们会经常使用的。code

var a = "0";
     var b = [];
     var c = {};
     var d = "";
     var e = 0;
     var f = null;
     var g;
     !!a; // true
     !!b; // true
     !!c; // true
     !!d; // false
     !!e; // false
     !!f; // false
     !!g; // false
复制代码

隐式强制类型转换

隐式强制类型转换指的是那些隐蔽的强制类型转换,反作用也不是很明显,会让代码变得晦涩难懂对象

字符串和数字之间的隐式强制类型转换

根据规范,若是某个操做数是字符串或者可以经过如下步骤转换为字符串 的话,+ 将进行拼接操做。若是其中一个操做数是对象(包括数组),则首先对其调用 ToPrimitive 抽象操做,该抽象操做再调用 [[DefaultValue]],以数字做为上下文。 若是 + 的其中一个操做数是字符串(或者经过以上步骤能够获得字符串), 则执行字符串拼接;不然执行数字加法ip

var a = 42;
     var b = a + "";
     b; // "42"
复制代码

这里有一个小差异须要注意:a + ""(隐式)和前面的String(a)(显式)之间有一个细微的差异须要注意。根据 ToPrimitive抽象操做规则,a + ""会对a调用valueOf()方法,而后经过ToString抽象 操做将返回值转换为字符串。而 String(a) 则是直接调用 ToString()。 例如:ci

var a = {
        valueOf: function() { return 42; },
         toString: function() { return 4; }
     };
     a + "";         // "42"
     String( a );    // "4"
复制代码

若是执行-操做,它们首先被转换为字符串(经过toString()),而后再转换为数字。

var a = [3];
     var b = [1];
     a - b; // 2
复制代码

布尔值到数字的隐式强制类型转换

如下状况中,非布尔值会被隐式强制类型转换为布尔值,遵循前面介绍过的 ToBoolean 抽 象操做规则

(1)if (..)语句中的条件判断表达式。

(2)for ( .. ; .. ; .. )语句中的条件判断表达式(第二个)。

(3) while (..) 和 do..while(..) 循环中的条件判断表达式。

(4)? :中的条件判断表达式。

(5) 逻辑运算符 ||(逻辑或)和 &&(逻辑与)左边的操做数(做为条件判断表达式)。

var a = 42;
     var b = "abc";
     var c;
     var d = null;
     if (a) {
         console.log( "yep" ); // yep
    }
    while (c) {
       console.log( "nope, never runs" );
     }
    c = d ? a : b; 
    c;  // "abc"
    if ((a && d) || c) {
      console.log( "yep" );  // yep
    }
复制代码

符号的强制类型转换

宽松相等(loose equals)== 和严格相等(strict equals)=== 都用来判断两个值是否“相 等”,可是它们之间有一个很重要的区别,特别是在判断条件上,即== 容许在相等比较中进行强制类型转换,而 === 不容许。

字符串和数字之间的相等比较

字符串和数字相互比较时,首先将字符中转换为数字再来比较。

(1) 若是 Type(x) 是数字,Type(y) 是字符串,则返回 x == ToNumber(y) 的结果。

(2) 若是 Type(x) 是字符串,Type(y) 是数字,则返回 ToNumber(x) == y 的结果

var a = 42;
     var b = "42";
     a == b // true
复制代码

其余类型和布尔类型之间的相等比较

字符串或数字等其余类型与布尔类型比较时,先将布尔类型转换为数字再来和字符串比较,接下来就是进行的字符串和数字之间的相等比较,再进行一轮转换来比较。

(1) 若是 Type(x) 是布尔类型,则返回 ToNumber(x) == y 的结果;

(2) 若是 Type(y) 是布尔类型,则返回 x == ToNumber(y) 的结果

var x = true;
     var y = "42";
     x == y; // false
复制代码

null 和 undefined 之间的相等比较

(1) 若是 x 为 null,y 为 undefined,则结果为 true。

(2) 若是 x 为 undefined,y 为 null,则结果为 true

在 == 中 null 和 undefined 相等(它们也与其自身相等),除此以外其余值都不存在这种 状况

var a = null;
    var b;
     a == b;     // true
     a == null;  // true
     b == null;  // true
     a == false; // false
     b == false; // false
     a == "";    // false
     b == "";   // false
     a == 0;  // false
     b == 0;  // false
复制代码

对象和非对象之间的相等比较

对象和非对象之间的比较,首先对对象进行ToPromitive转换,再进行比较。

(1) 若是 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x == ToPrimitive(y) 的结果;

(2) 若是 Type(x) 是对象,Type(y) 是字符串或数字,则返回 ToPromitive(x) == y 的结果

var a = 42;
   var b = [ 42 ];
   a == b; // true
复制代码

比较少见的状况

1.隐式转换返回其余数字

Number.prototype.valueOf = function() {
         return 3;
     };
     new Number( 2 ) == 3;   // true
复制代码

Number(2) 涉及 ToPrimitive 强制类型 转换,所以会调用 valueOf()返回3.

思考题:下面代码中 a 在什么状况下会打印 1?

var a = ?;
if(a == 1 && a == 2 && a == 3){
 	conso.log(1);
}
复制代码
  1. 完整性检查
"0" == null;           // false
        "0" == undefined;      // false
        "0" == false;          // true -- 晕!
        "0" == NaN;            // false
        "0" == 0;              // true
        "0" == "";             // false
        false == null;         // false
        false == undefined;    // false
        false == NaN;          // false
        false == 0;            // true -- 晕! 
        false == "";           // true -- 晕!
        false == [];           // true -- 晕!
        false == {};           // false
        "" == null;            // false
        "" == undefined;       // false
        "" == NaN;             // false
        "" == 0;               // true -- 晕! 
        "" == [];              // true -- 晕!
        "" == {};              // false
        0 == null;             // false
        0 == undefined;        // false
        0 == NaN;              // false
        0 == [];               // true -- 晕! 
        0 == {};               // false
        [] == ![]              // true -- 反人类
复制代码

咱们能够来看看[] == ![] 的转换过程,基本就能明白

[] == ![] // =>
[] == false // => 
[] == 0 // =>
0 == 0 // true
复制代码

按照上述规范推敲两边的值,基本就不会出错。而且这两个原则可让咱们有效地避免出错

• 若是两边的值中有 true 或者 false,千万不要使用 ==。

• 若是两边的值中有 []、"" 或者 0,尽可能不要使用 ==。

参考连接:《你不知道的javascript》

相关文章
相关标签/搜索