3、数据类型转换

215 阅读4分钟

基本小知识

 *   ==相等  ===绝对相等
 *   ==在比较的时候,如果两边类型不一致,则转换为相同的数据类型
 *    *** caniuse网站用来检测兼容性:
 *     NaN==NaN  false    Object.is(NaN,NaN)->true
 *     null==undefined -> true    null===undefined -> false   null&undefined和其他任何值比较都是不相等的
 *     对象==字符串   对象转换为字符串
 *     剩余的情况都是转换为数字
 * 
 *   ===类型不一致,不会转换,直接false

一、对象转换为数字/字符串「字符串拼接、数学运算、特殊方法处理、==比较(隐式转换、显式转换)

// *********下面这段话很重要:

// + 首先检测对象的 Symbol.toPrimitive 这个属性,获取其原始值 // + 如果没有这个属性,则继续调用它的valueOf,也是获取原始值 // + 如果值不是原始值,则继续调用toString转换为字符串 // + 再把字符串基于Number转换为数字

 let obj = {
    name: 'xxx'
 };
 console.log(obj - 10); //数学运算:先把obj隐式转换为数字,再进行运算 */

let obj = {
    name: 'xxx',
    [Symbol.toPrimitive](hint) {
        // hint检测到浏览器隐式规定的转换类型:'number'/'string'/'default'
        return 10;
    }
};
console.log(obj - 10); 

练习题:让下面的代码成立

if (a == 1 && a == 2 && a == 3) {
    console.log('OK');
} 

第一类方案:隐式进行数据类型转换的时候进行处理的

1、重写[Symbol.toPrimitive]

var a = {
    i: 0,
    //[Symbol.toPrimitive]这个值也可以变为toString和valueOf
    [Symbol.toPrimitive]() {
        return ++this.i;
   }
};

2、相当于重写toSting()方法

 var a = [1, 2, 3];
// a.shift() -->1
a.toString = a.shift;
if (a == 1 && a == 2 && a == 3) {
    console.log('OK');
} 

第二类:ES6 数据劫持

let obj = {};
Object.defineProperty(obj, 'name', {
    // 以后当我们操作对象的name属性的时候(获取或者设置),触发getter/setter
    get() {
        return '逗你玩';
    },
    set(value) {
        console.log(value);
    }
}); 



// var a = 12; //全局上下文中,基于var/function声明变量,也相当于给window设置了属性 window.a=12
var i = 0;
Object.defineProperty(window, 'a', {
    get() {
        return ++i;
    }
});
if (a == 1 && a == 2 && a == 3) {
    console.log('OK');
} 

二、其它的数据类型转换为number类型

例如:==比较、数学运算(+不仅仅是数学运算,还有字符串拼接)

1、显式转换方案:

Number([val]) -> 隐式转换一般调取的都是这个方法「浏览器有自己的特殊处理,针对于每一种情况都有详细的规则」

2、parseInt 和Number区别

 parsetInt/parseFloat([val])
 
 parsetInt([val],[radix])处理机制:
    (1[val] 必须是一个字符串,如果不是,则也要默认转换为字符串
    (2[radix]不设置(或者写的是零):正常都是按照10处理的,如果字符串是以”0x“开始的,默认值是16...
    (3)先在[val]中,找到所有符合[radix]进制的内容(从左到右查找,直到遇到不符合的为止「不论后面是否还有符合进制的,都不在查找了」),然后再把找到的内容看做[radix]进制,转换为十进制
    (4[radix]范围  2~36,除了0以外(0->10/16),不在这个范围内,结果都是NaN

3、练习

parseInt('12px') ->  parseInt('12px',10) -> 在字符串中找到所有符合10进制的内容 ‘12’ -> 最后把'12'当做看做10进制,转换为10进制 -> 12

parseInt('12px',1) -> NaN   //[radix]范围  2~36,除了0以外(0->10/16),不在这个范围内,结果都是NaN

console.log(parseInt(null)); //->parseInt('null',10) -> NaN  

// 把其它进制转换为10进制?
// '10101'  2机制 -> 10进制
// 1*2^0 + 0*2^1 + 1*2^2 + 0*2^3 + 1*2^4

4、继续练习

把一个函数作为值传递给另外一个函数执行(实参):回调函数
1parseInt(27.2,0)

==> parseInt('27.2') -> 27
2parseInt(0,1)

==> NaN  进制从2-36 其余的全是NaN
3parseInt('0013',2)

  '001' 看做2进制 转换为10进制
  1*2^0 -> 1
4parseInt('14px',3)

 '1' 看做3进制 转换为10进制
  1*3^0 -> 1  
5parseInt(123,4)

  parseInt('123',4)
  '123' 看做4进制 转换为10进制
  3*4^0 + 2*4^1 + 1*4^2 -> 3+8+16 -> 27  
  
6、最好看一下map的源码

三、把其他的类型转换成布尔

 * 把其它数据类型转换为布尔:
 *   只有”0/NaN/null/undefined/空字符串“ 转换为false,其余都是true
 *   例如:
 *     if(1){} 
 *     ! 取反
 *     !! 转换为布尔

四、“+”

1、 ”+“作为字符串拼接

 *  两边都有值,有一边出现字符串或者对象,则为字符拼接
 *  特殊:{}+10 -> 10  {}看做代码块(ES6 块级上下文),真正运算的只有 +10 ->10
 *  ({}+10) -> '[object Object]10'

2、 +只有一边或者++x再或者x++,都是数学运算

  10+(++x) -> 先把x累加1,然后和10运算
  10+(x++) -> 先拿x的值和10运算,最后再x累加1

3、练习题

let result = 100 + true + 21.2 + null + undefined + "Tencent" + [] + null + 9 + false;
console.log(result);

// 10+{} -> "10[object Object]"  原本是想把{}变为数字,但是Symbol.toPrimitive/valueOf/toString,调到toString变为字符串,此时符合了有一边变为字符串了,则是字符串拼接

let x = '10';
console.log(++x); //->11

x = '10';
x += 1; //->x=x+1
console.log(x); //->'101'