Skip to content

Latest commit

 

History

History
473 lines (384 loc) · 11.9 KB

11数据类型转换.md

File metadata and controls

473 lines (384 loc) · 11.9 KB

数据类型转换

分为显示强制类型转换隐式强制类型转换

[] == false结果为ture???
'true' == true结果为false???
[] == ![]结果为true???
[3] - [1]结果为2???

想知道原因吗?下面来一探究竟吧!

显示强制类型转换

自己显示调用类型转换的方法,被称为显示强制类型转换

转为number

调用Number(),处理失败返回NaN

  • number转换为number
      // 结果不变
      console.log(Number(1)); // 1
  • string转换为number
      // 可解析成数字 -> 数字
      console.log(Number('1')); // 1
    
      // 空字符串 -> 0
      console.log(Number('')); // 0  里面有空格也是0
    
      // 不可解析成数字 -> NaN
      console.log(Number('str')); // NaN
  • boolean转换为number
      // true -> 1
      console.log(Number(true)); // 1
    
      // false -> 0
      console.log(Number(false)); // 0
  • null转换为number
    // null -> 0
    console.log(Number(null)); // 0
  • undefined转换为number
    // undefined -> NaN
    console.log(Number(undefined)); // NaN
  • object转换为number
    • 调用自身的valueOf()ObjectvalueOf()如果没有被改写,返回自身)
      • 返回基本类型值,对返回值调用Number()
      • 返回对象类型值,重新调用自身toString()
        • 返回基本类型值,对返回值调用Number()
        • 返回对象类型值,抛出TypeError
    // 模拟 Object 转换数字的过程
    var obj = {};
    
    // 调用valueOf()
    var val = obj.valueOf(); // {}
    
    // 返回对象类型,再调用toString()
    var res = obj.toString(); // '[object Object]'
    
    // 返回基本类型 字符串
    console.log(Number(res)); // NaN
    
    // 与直接调用结果一直
    console.log(Number(obj)); // NaN

Number() 和 parseInt() 的区别是什么?

Number()

Number()是强制转换,转换的字符串中,出现非数字字符会转换失败,返回NaN

console.log(Number('1a')); // NaN
console.log(Number('1.3')); // 1.3
parseInt()

parseInt()是解析,允许解析的字符串中包含非数字字符。从左到右解析,遇到非数字字符就停止。

  • parseInt()先将参数强制转换成字符串再进行解析(即便传递的是数字)
  • parseInt()方法第二个参数,表示要解析的数字的基数。该值介于 2 ~ 36 之间
console.log(parseInt('1a')); // 1
console.log(parseInt('1.3')); // 1

转为string

调用String()

  • number转换为string
      // 转为对应string
      console.log(String(1)); // '1'
  • string转换为string
      // 保持不变
      console.log(String('str')); // 'str'
  • boolean转换为string
      // true -> 'true'
      console.log(String(true)); // 'true'
    
      // false -> 'false'
      console.log(String(false)); // 'false'
  • null转换为string
    // null -> 'null'
    console.log(String(null)); // 'null'
  • undefined转换为string
    // undefined -> 'undefined'
    console.log(String(undefined)); // 'undefined'
  • object转换为string
    • 调用自身的toString()数组toString()是例外,将元素转为字符串后用,连接)
      • 返回基本类型值,对返回值调用toString()
      • 返回对象类型值,重新调用自身valueOf()
        • 返回简单类型值,对返回值调用toString()
        • 返回对象类型值,抛出TypeError
    // 模拟 Object 转换字符产的过程
    var obj = {};
    
    // 调用toString()
    var res = obj.toString(); // '[object Object]'
    
    // 返回基本类型 字符串
    console.log(res.toString()); // '[object Object]'
    
    // 与直接调用结果一直
    console.log(String(obj)); // '[object Object]'

转为boolean

调用Boolean()或者!!

  • 转为false的值
    • undefined
    • null
    • NaN
    • -0 / +0
    • ''
  • 转为true的值
    • 转为false之外的值,都转为true

转为Array

有两种方法把类数组字符串转换为数组

  • .split()

    /**
      * 把 字符串 分割成 字符串数组,不改变原字符串
      * 
      * 常用的第一个参数:字符串或正则表达式,从该参数指定的地方分割。
      * 若值为''则每个字符之间都会被分割
      */
    var str = 'ab';
    var str1 = 'a, b';
    
    console.log(str.split('')); // [a, b]
    console.log(str1.split(',')); // [a, b]
  • Array.prototype.slice.call()

    /** .slice()方法根据传递的参数截取数组,
      * 并把结果以新数组的形式返回,不改变原数组
      * 
      * 根据这个特性,可以对非数组形式的数组,
      * 调用Array的slice方法,实现转换
      */
    var str = 'ab'
    
    var arr = Array.prototype.slice.call(str);
    
    console.log(arr); // [a, b]
  • Array.from()

    /** Array.from()方法对一个类似数组或可迭代对象创建一个新的,
     * 浅拷贝的数组实例
    **/
    var set = new Set();
    
    set.add('a');
    set.add('b');
    
    var arr = Array.from(set);
    
    console.log(arr); // [a, b]

隐式强制类型转换

系统默认根据一定的规则,自行转换的模式称为隐式强制类型转换
总是返回简单类型值。发生在运行时。
作用:减少冗余,让代码更简洁,但不正确的使用会增加阅读难度,请酌情使用

四则运算的隐式转换逻辑

加(+)

由于+既能用于数字相加,也能用于字符拼接,所以有两种处理情况

一元形式

+运算符的一元形式,会把+后的转换为数字

console.log(+"23333"); // 23333
拼接操作

多个值拼接,其中有一个值字符串或可以根据ToPrimitive规则转为字符串+将进行拼接操作,否则执行number + number

ToPrimitive规则

  • 调用自身的valueOf()
    • 返回基本类型值,对返回值调用toString()
    • 返回对象类型值,重新调用自身的toString()
      • 返回简单类型值,对返回值调用toString()
      • 返回对象类型值,抛出TypeError

ToPrimitive规则objectstring不同,objectstring先调用toString(),再调用valueOf()

var str = 66 + ''; // 或者 '' + 66
console.log(str); // '66'

// 数组转换
var str1 = [1, 2] + [2, 3];
console.log(str1); // '1,22,3'

减乘除(- * /)

- * / 只能用于数字运算

console.log('66' - 0); // 66

// 数组转换
var num = [3] - [1];
console.log(num); // 2

var num1 = [3, 1] - [1, 2];
console.log(num1); // NaN

隐式转为Boolean的场景

if()for()while()(三目运算 ? :)||&&=====

隐式转换的规则与显示转换的规则一致

  • if()while ():括号内不是boolean,转为boolean

  • for (..; ..; ..):第二个位置不是boolean,转为boolean

  • ? :?前面不是boolean,转为boolean

  • ||&&:左边的操作数,不是boolean,转为boolean

  • =====:操作的结果为boolean

    宽松相等和严格相等的区别:  
    `===`比`==`强制类型转换确实要多花点时间,但仅仅是微秒级的差别(百万分之一秒)。两者使用相同算法,除了JS引擎实现上的细微差别,两者并没有什么不同
    

==的隐式转换逻辑

==允许在比较中进行强制类型转换

字符串 == 数字 转换逻辑

字符串的转为数字进行比较

console.log('1.23' == 1.23); // true

其它类型 == 布尔值 转换逻辑

Boolean值转为数字进行比较

会有以下几种情况:

  • 字符串 == 布尔值(走字符串 == 数字 转换逻辑
      /**
        * '0' == false; // false转数字  Number(false)
        * =>
        * '0' == 0; // '0'转数字  Number('0')
        * =>
        * 0 == 0; // true
        */
      console.log('0' == false); // true;
  • 数字 == 布尔值
      /**
        * 0 == false; // false转数字  Number(false)
        * =>
        * 0 == 0; // true
      **/
      console.log(0 == false); // true;
  • 对象 == 布尔值(走对象 == 非对象 转换逻辑
    /**
      * [] == false; // false转数字  Number(false)
      * =>
      * [] == 0; // []使用ToPrimitive规则
      * =>
      * '' == 0; // ''转数字 Number('')
      * => 
      * 0 == 0; // true
      */
    console.log([] == false); // true;

非对象 == 对象 转换逻辑

有对象,把对象用ToPrimitive()规则转换成字符串

  • 数字 == 对象
    /**
      * 33 == [33]; // [33]使用ToPrimitive规则
      * =>
      * 33 == '33'; // '33'转数字 Number('33')
      * =>
      * 33 == 33; // true
      */
    console.log(33 == [33]); // true
  • 字符串 == 对象
    /**
      * '33' == [33]; // [33]使用ToPrimitive规则
      * =>
      * '33' == '33'; // true
      */
    console.log('33' == [33]); // true

对象 == 对象 转换逻辑

对象是进行地址比较,不发生强制类型转换

// 会开辟两个空间,地址不同
console.log([1,2]  ==  [1,2]); // false

// 地址相同情况
var a = [1,2];
var b = a;
console.log(a == b); // true

null == undefined 转换逻辑

null == undefinef结果为true,其他值没这种情况。

console.log(null == undefined); // true

// 可以判断a为null和undefined
var a;
console.log(a == null); // true

===的隐式转换逻辑

不允许在相等比较中进行强制类型转换。
先判断类型,类型不同直接false。

建议:(因为会出现一些不能直观理解的场景)

  • 两边值中有truefalse 不要用==
  • 两边值中有[]0不要用==

常见隐式转换题目

/**1
  * 'true' == true; // true转为数字
  * =>
  * 'true' == 1; // 'true'转为数字
  * =>
  * NaN == 1; // false
  */
console.log('true' == true); // false


/**2
  * [] == ![]; // ![]转为布尔值
  * =>
  * [] == false; // false转为数字
  * =>
  * [] == 0; // [] 使用ToPrimitive规则
  * =>
  * '' == 0; // ''转为数字
  * =>
  * 0 == 0; // true
  */
console.log([] == ![]); // true


/**3
  * [] + []; // []使用ToPrimitive规则
  * =>
  * '' + ''; // ''
  */
console.log([] + []); // ''


/**4
  * [] + {}; // []和{}使用ToPrimitive规则
  * =>
  * '' + '[object Object]'; // '[object Object]'
  */
console.log([] + {}); // '[object Object]';


/**5
  * 根据浏览器不同,有两种情况
  * chrome:
  * {} + []; // {}和[]使用ToPrimitive规则
  * =>
  * '[object Object]' + ''; // '[object Object]'
  * 
  * FireFox
  * {} + []; // {}被当成代码块执行
  * =>
  * +[]; // []转为数字
  * =>
  * +0; // 0
  */
console.log({} + []); // '[object Object]' 或者 0;


/**6
  * 根据浏览器不同,有两种情况
  * chrome:
  * {} + {}; // {}使用ToPrimitive规则
  * =>
  * '[object Object]' + '[object Object]'; // '[object Object][object Object]'
  * 
  * FireFox:
  * {} + {}; // 第一个{}被当成代码块
  * =>
  * + {}; // {}转为数字
  * => +NaN; //NaN
  */
console.log({} + {}); // '[object Object][object Object]' 或者 NaN


/**7
  * true + true; // 此情况执行number + number。true转为数字
  * =>
  * 1 + 1; // 2
  */
console.log(true + true); // 2


/**8
  * 1 + { a: 1 }; // { a: 1 }使用ToPrimitive规则
  * =>
  * 1 + '[object Object]'; // 1转为字符串
  * => 
  * '1' + '[object Object]'; // '1[object Object]'
  */
console.log(1 + { a: 1 }); // '1[object Object]'