{} + [],[]+{}傻傻分不清?一招制伏js的数据类型转换

简言

最近被 [ ] + { } 和 { } + [ ] 弄得有点晕,当时感觉理解了,过一段时间就会忘记。可能是没get到内部运行机制的原理,还是一知半解的水平。所以,又去重新啃了一下js的基础知识,终于,被我发现诀窍了。从此,js的数据类型转换不再晕头转向了。

正文开始

1. js的数据类型:

js的数据类型包含原始类型和引用类型

原始类型(7种):Number、String、Boolean、undefined、null、Symbol、BigInt

引用类型:Object

2、显式类型转换

  • Number()

原始类型转换为Number类型的转换规则:

数值:转换后还是原来的值

字符串:如果可以被解析为数值,则转换为对应的数值,否则,转换为NaN,需要注意的是:空字符串转换为0

undefined:转换为NaN   

null:转换为0

布尔:true转换为1,false转换为0

Symbol:会报错,Symbol类型的值不能转成为Number,报类型错误
复制代码

引用类型转换为Number类型的转换规则:

如果要转换的是个对象,先调用对象的valueOf方法,如果该方法返回的是原始类型的值,那么依照上述规则,进行类型转换,如果方法返回的还是复合类型,那么调用该对象的toString方法,如果toString方法返回的是原始类型的值,按上述规则进行转换,如果不是,则报错

通过几个案例加深一下印象吧:

 Number({a:1}) 
 // valueOf() -> {a:1} -> toString() -> '[object Object]' -> Number('[object Object]')-> NaN
 Number([1,2]) 
 // valueOf() -> [1,2] -> toString() -> '1,2' -> Number('1,2')-> NaN 
 Number([1])  
 // valueOf() -> [1] -> toString() -> '1' -> Number('1') => 1
 Number([]) 
 // valueOf() -> []  -> toString() -> '' -> Number('') => 0
 Number(function(){}) 
 // valueOf() -> function(){}  -> toString() -> 'function(){}' ->  Number('function(){}') => NaN
复制代码
  • String()

原始类型转换为String类型的转换规则:

数值:转换为数值字符串

字符串:字符串

undefined:转换为'undefined'

null: 转换为'null'

boolean:转换为'true'或'false'

Symbol:转换为'Symbol()'

引用类型转换为String类型的转换规则:

如果要转换的是个对象,那么先调用对象的toString方法,如果方法返回的结果是个原始类型,则按上述规则转换,如果结果返回的结果还是对象类型,那么会调用对象的valueOf方法,如果方法返回的是原始类型,依旧按照上述规则转换,如果返回的还是对象类型,那么转换报错

通过几个案例加深一下印象吧:

  var a1 = { b : 1 };
      a1.toString() // '[object Object]'
      console.log(String(a1)) // '[object Object]'

  var a2 = [1,2,3];
      a2.toString() // '1,2,3'
      console.log(String(a2)) // '1,2,3'

  var a3 = function(){};
      a3.toString() // 'function(){}'
      console.log(String(a3)) // 'function(){}'
        
  var a4 = [];
      a4.toString() // ''
      console.log(String(a4)) // ''
复制代码
  • Boolean()

转换为Boolean类型就比较简单了,记住这些就行了:

undefined: false

null: false

NaN : false

'': false

0 : false

除了上述列出来的这些,其余的都转换为true

3、隐式类型转换

触发隐式类型转换的行为: 四则运算、判断语句、native调用(console.log和alert方法会内部调用String方法)。

四则运算中除了加法(+),其他的运算符(-*/%)都会把非Number类型转换为Number类型

+:作为算术运算符,会把其他类型通过Number()转换为数值类型;当+两边有一边是字符串时,会被当做是字符串连接符,那么其他类型通过String()转换为字符串类型。

   1 + 2 //3
    // 两边都是Number类型
   1 +'' // '1'
    // 有字符串,其他类型转换为字符串
   1+ false // 1
    // 其他类型先转换为Number类型,再相加
    1+ null //1
     // 其他类型先转换为Number类型,再相加
    1+ undefined  //NaN
    // 其他类型先转换为Number类型,再相加
    1 + function(){} //'1function(){}'
    //引用类型先转换为值类型,再根据值类型进行相加
    1 + {} //'1[object Object]'
     //引用类型先转换为值类型,再根据值类型进行相加
    1 + [] //'1'
    //同上
    1 +[1,2] // '11,2'
    //同上
    
复制代码

==

  NaN不等于任何值
  String和Number进行比较时,String转换为Number
  Boolean和其他类型进行比较时,Boolean转换为Number
  null和undefined进行比较时,相等
  引用类型和值类型比较时,引用类型先转换为值类型(内部调用toPrimitive)
  引用类型和引用类型比较时,判断是否指向同一个引用
复制代码

先看几个比较坑的例子:

    [] == [] //false
    // 引用类型比较,不指向同一个引用为false
    [] == 0  // true
    // [] 转换为值类型为'' ,''== 0时,Number('') -> 0,所以为true
    ![] == 0 // true
    // ![]为false,Number(false) -> 0 ,所以为true
    ![] == [] //true
     // ![]为false,[]转换为值类型为'',false转换为Number(false) -> 0,''转换为Number('') -> 0,所以为true
    
    {} == !{} //false
    //!{} 为false,{}转换为值类型为'[object Object]',false转换为Number(false) -> 0,'[object Object]'转换为NaN,所以为false
    {} == {} //false
     // 引用类型比较,不指向同一个引用为false
    
复制代码

4、经典面试题

    {} + {} //'[obiect Obiect][obiect Obiect]'
    {} + [] // 0
    [] + {} //[obiect Obiect]
    [] + [] //''

复制代码

对于{} + {},在火狐浏览器上打印得出的结果是NaN

5、不得不提的toPrimitive函数

toPrimitive(input,PreferredType):将一个对象转换为值类型

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

toPrimitive()的执行机制:其实就是将一个引用类型的值转化为原始值,可能是字符串和数值,转换规则如上文中引用类型转换为String类型的转换规则引用类型转换为Number类型的转换规则一致。

input是要转换的对象,当input是一个原始值,直接返回input

PreferredType是期望转换为类型,可以是字符串或数值。

unction ToPrimitive(input,PreferredType) {
    var hint = PreferredType || 'default';
 
    // 如果是原始值,直接返回
    if( isPrimitiveType(input)){ 
        return input 
    }
    if(typeof input === 'symbol'){
        throw new Error('typeError')
    }
    if(input instanceof Date){
        hint = 'string'
    }
    if (hint == "number" || hint == 'default') {
      var res = input.valueOf();
     !isPrimitiveType(res) && (res = res.toString());
      if(isPrimitiveType(res)){
          return res
      }else{
        throw new Error('typeError')
      }
    }
    if (hint == "string") {
        var res = input.toString();
        !isPrimitiveType(res) &&  (res = res.valueOf());
      if(isPrimitiveType(res)){
          return res
      }else{
        throw new Error('typeError')
      }
    }
    function isPrimitiveType(input){
        var primitiveType = ['string','undefined','number','boolean'];
        return  (input === null || primitiveType.indexOf(typeof input) !== -1);
    }
  }
复制代码

猜你喜欢

转载自juejin.im/post/7033267746011873316