zoukankan      html  css  js  c++  java
  • javascript: 类型转换

    strat


    javascript 的类型转换一直是个大坑,但其实它也减少了代码量。

    ToPrimitive


    Symbol.toPrimitive 是一个内置的 Symbol 值,它作为对象的函数值属性存在,当一个对象转换为原始值时,会调用此函数。

    该函数被调用时,会被传递一个字符串参数 hint ,表示要转换到的原始值的预期类型。 hint 参数的取值是 "number""string""default" 中的任意一个。

    // 一个没有提供 Symbol.toPrimitive 属性的对象,参与运算时的输出结果
    let obj1 = {};
    console.log(+obj1);     // NaN
    console.log(`${obj1}`); // "[object Object]"
    console.log(obj1 + ""); // "[object Object]"
    
    // 接下面声明一个对象,手动赋予了 Symbol.toPrimitive 属性,再来查看输出结果
    let obj2 = {
      [Symbol.toPrimitive](hint) {
        if (hint == "number") {
          return 10;
        }
        if (hint == "string") {
          return "hello";
        }
        return true;
      }
    };
    console.log(+obj2);     // 10      -- hint 参数值是 "number"
    console.log(`${obj2}`); // "hello" -- hint 参数值是 "string"
    console.log(obj2 + ""); // "true"  -- hint 参数值是 "default"
    

    从上面可以看出,toPrimitive 转换过程依靠 hint 参数:

    • number: valueOf() → toString() → TypeError
    • string: toString() → valueOf() → TypeError
    • default: 同 number

    valueOf

    对象 返回值
    Array 返回数组对象本身。
    Boolean 布尔值。
    Date 存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC。
    Function 函数本身。
    Number 数字值。
    Object 对象本身。这是默认情况。
    String 字符串值。
    Symbol Symbol本身
    Math 和 Error 对象没有 valueOf 方法。

    toString

    对象 返回值
    Array [1, 2, 3] => "1,2,3"
    Boolean false => "false"
    Date 返回表示 UTC 的字符串。
    Function 返回表示当前函数源代码的字符串。
    Number 返回表示当前数值的字符串。
    Object "[object Object]"
    String 字符串本身。
    Symbol "Symbol()"

    注意:[null].toString()以及[undefined].toString()均返回空字符串""

    ToBoolean


    ES5 规范 9.2中列举了布尔强制类型转换 (ToBoolean) 会出现假值 (false) 的仅有以下几个,其余都为真值 (true):

    • undefined
    • null
    • false
    • +0、-0、NaN
    • ''(空字符串)
    /*
     以下 a、b、c 存储的是指向对象的指针,并非假值
    */
    let a = new Number(0);
    let b = new Boolean(false);
    let c = new String('');
    
    Boolean(a) // true
    Boolean(b) // true
    Boolean(c) // true
    
    Boolean(0) // false
    Boolean(false) // false
    Boolean('') // false
    

    ToNumber


    对象 返回值
    Undefined NaN
    Null 0
    Boolean true => 1, false => 0
    Number 返回自身
    String 不能解析为 StringNumericLiteral 的,均返回 NaN
    Object ToPrimitive(input argument, hint Number)

    注: StringNumericLiteral

    强制类型转换符


    加号 (+)

    +作为一元运算符,单独使用,会强制将右侧操作数类型转为 number,即对右侧操作数使用 ToNumber()。

    +1 // 1
    +'1.2' // 1.2
    +[] // 0
    +[1, 2, 3] // NaN
    +{} // NaN
    

    叹号 (!)

    !会强制将右侧操作数类型转为 boolean,并反转真、假值,即对右侧操作数使用 !ToBoolean()。

    !true // false
    !0 // true
    ![] // false
    !'' // true
    !undefined // true
    !null // true
    
    !!true // true
    !!undefined // false
    !!null // false
    

    四则运算符


    加法运算遵循以下规则:

    1. 运算的其中一方为字符串,就会把另一方转换为字符串。

      1 + '1' // '11'
      42 + '' // '42'
      
    2. 如果其中一方不是字符串或数字,就会将它转换为字符串或数字。

      false + true // 1
      3 + [1, 2, 3] // '31,2,3'
      ([] + {}) // '[object Object]'
      
      /* {} + [] 的结果为 0, 是因为从左往右解析,{} 为一个代码块,+[] 被解析为将 [] 转为 number, 即 0。*/
      {} + [] // 0
      ({} + []) // "[object Object]"
      

      注意:

      /* 会出现以下情况,是因为 + 'b' 解释为 ToNumber('b') */
      'a' + + 'b' // "aNaN"
      

    对于加法运算以外的运算来说,双方会被转为数字进行运算。

    1 * '2' // 2
    [] * {} // NaN
    1 * [1, 2, 3] // NaN
    
    let obj = {
    	valueOf: () => {
    		return 1
    	}
    }
    
    obj * 2 // 2
    

    == and ===


    对于==(相对等于)、===(绝对等于),绝大部分的书籍和博客都解释为前者仅检查值是否相等,后者检查值和类型是否相等,其实这样是不对的,正确的解释应该是:前者允许在比较的时候进行强制类型转换,后者不允许

    ES5 规范 11.9.3 定义了相对等于的行为,涵盖了所有的类型,具体可分为以下几种情况:

    1. 双方类型相同

      类型 结果
      Undefined true
      Null true
      Number 1. 如果其中一方为NaN,返回false。2. 如果 x 与 y 的值相同,则返回true,否则false。3.如果其中一方为+0-0且另一方为+0-0,返回true
      String 双方为完全相同的字符序列,返回true。否则返回 false
      Boolean 双方为truefalse,返回true,否则返回false
      Object 双方引用同一个对象,返回 true。否则,返回false
      NaN == NaN // false
      -0 == +0 // true
      
    2. null 与 undefined

      null == undefined // true
      
    3. 字符串与数字

      会将字符串转为数字进行比较,即ToNumber(字符串) == 数字

      10 == '10' // true
      10 == 'a' // false
      /* 十六进制 '0xa' => 十进制 10 */
      10 == '0Xa' // true
      
    4. 布尔类型与其他类型

      会将布尔类型转为数字,再与其他类型进行比较,即ToNumber(布尔类型) == 其他类型

      0 == false // true
      '1' == true // true
      null == false // false
      undefined == false // false
      
    5. 对象类型与非对象类型

      会将对象类型转为原始类型,再进行比较,即 ToPrimitive(对象类型) == 非对象类型

      [1] == 1 // true
      [1, 2] == 1 // false
      
      /* b.toString() 返回 '111' */
      let a = '111';
      let b = Object(a);
      a == b // true
      
      /* null 与 undefined 不能被封装为 object, 即 Object(null) 的返回结果与 Object() 的一样 */
      let c = null;
      let d = Object(c);
      c == d // false
      
      let e = undefined;
      let f = Object(e);
      e == f // false
      
    6. 以上都不是

      直接返回false.

      null == 0 // false
      undefined == 0 // false
      

    难以理解的情况


    1. [] == ![]

      [] == ![] // true
      
      /*
      第一步: !的优先级比 == 高,所以 ![] 解析为 !Boolean([]),结果为 true.
      现在: [] == true
      
      第二布: 布尔类型与其他类型进行比较,解析为 ToNumber(true), 结果为 0.
      现在: [] == 0
      
      第三步: 对象类型与非对象类型进行比较,解析为 ToPrimitive([], 'number'),结果为 0.
      现在: 0 == 0 // true
      */
      
    2. [null] == ''

      [null] == '' // true
      [undefined] == '' // true
      
      /*
      [null].toString() 以及 [undefined].toString() 均返回空字符串 ''
      因为 null 与 undefined 均没有 toString 和 valueOf 方法。
      */
      
    3. 0 == ' '

      0 == '
      ' // true
      0 == '	
      ' // true
      
      /*
      上述语句被解析为 ToNumber('
      '), 返回结果为 0.
      */
      

      具体解释:' ' == 0 is true?

    备注


    理解了类型转换,你会发现并非一定要抛弃==去使用===

  • 相关阅读:
    FZU 2150 Fire Game
    POJ 3414 Pots
    POJ 3087 Shuffle'm Up
    POJ 3126 Prime Path
    POJ 1426 Find The Multiple
    POJ 3278 Catch That Cow
    字符数组
    HDU 1238 Substing
    欧几里德和扩展欧几里德详解 以及例题CodeForces 7C
    Codeforces 591B Rebranding
  • 原文地址:https://www.cnblogs.com/guolao/p/11364779.html
Copyright © 2011-2022 走看看