美文网首页
Javascript学习笔记-强制类型转换

Javascript学习笔记-强制类型转换

作者: Patrick浩 | 来源:发表于2017-09-16 12:14 被阅读0次
    Javascript类型转换.png

    1. 基本类型转换

    由于Javascript中存在七种基本类型:number, string , boolean , object, null, undefined, symbol,在使用过程中会有意识和无意识的在 运行时 存在相互转换。

    1.1 toString

    1.1.1 较大数和较小数

    当数字处于较大或较小时,由于Javascript会将数字转换为科学记数法方式记录,这个时候如果对其进行转换为字符串,那么显示结果是科学记数法的字符串

    console.log(String(0.0000000001)); // '1e-10'
    console.log(String(10000000000000000000000)); // '1e+22'
    
    1.1.2 对象的toString

    一般对象的toString方法,将会显示该对象的[[class]]

    Object.prototype.toString.call({}); // '[object Object]'
    Object.prototype.toString.call(function(){}) // '[object Function]'
    
    1.1.3 数组的toString

    数组由于自身重写过toString方法,数组的toString方法会返回逗号连接的字符串

    Array.prototype.toString.call(['1', 'a', {'a': 1}]); // '1,a,[object Object]'
    
    1.1.4 JSON.stringify()

    JSON.stringify()方法用于将数据转换为JSON格式的字符串,但是对于undefined, function, symbol类型的数据,在转换时会选择抛弃,从而返回undefined

    JSON.stringify(undefined); // undefined
    JSON.stringify(function(){}); // undefined
    JSON.stringify(Symbol('test')); // undefined
    

    转换对象在数组中时,这些值会被赋值为null

    JSON.stringify([undefined, 1, function(){}]); // [null, 1, null]    
    

    如果转换对象出现循环引用,那么在转换的时候会抛出异常。
    为了使得我们所有的对象在转换成JSON字符串的时候可以正常转换,我们可以定义toJSON方法,该方法在JSON.stringify调用前会进行调用,对数据进行处理

    var a = {a: 1, b: 2};
    a.toJSON = function() {
        return {a: 1}
    }
    JSON.stringify(a); // "{"a": "1"}"
    

    JSON.stringify一共可以接受三个参数,除了第一个参数为转换对象以外,第二个参数可以接收了一个数组或者方法对转换对象属性进行过滤,第三个参数则可以将JSON字符串进行格式化

    var a = {a: 1, b: 2};
    // 第二个参数使用数组进行过滤
    JSON.stringify(a, ['a']); // "{"a": "1"}"
    // 第二个参数使用function,自身对象会先调用方法一次后,每个属性调用一次,返回undefined时则过滤掉该属性
    JSON.stringify(a, (k, v)=>{
        if (k!=='a') {
          return v;
        }
    }); // "{"b": 2}"
    // 第三个参数进行格式化,接收数字时每个层级添加相应数目空格
    JSON.stringify({a:1, b:2, c: {a: 1}}, null, 2);
    // 第三个参数如果为字符串,则每个层级添加该字符串,能添加的字符串最大长度为10
    JSON.stringify({a:1, b:2, c: {a: 1}}, null, '--');
    

    1.2 toNumber

    1.2.1 基本类型转Number

    基本类型转为number,按照以下规则转换:

    // null , false , '' 转换为0
    console.log(Number(null)); // 0
    console.log(Number(false)); // 0
    console.log(Number('')); // 0
    // true转换为1
    console.log(Number(true)); // 1
    // undefined转换为NaN 
    console.log(Number(undefined)); // NaN
    // 字符串如果是数字格式则会进行转换
    console.log(Number('123')); // 123
    
    1.2.2 对象转Number

    遵循toPrimitive的规则,如果对象存在valueOf方法,则调用该方法,如果调用后返回的结果为基本类型,则按照 1.2.1 基本类型转Number 规则进行转换;如果返回不为基本类型或者不存在valueOf方法,则调用toString方法后,按照 1.2.1 基本类型转换Number 规则进行处理

    var a = [1]; 
    // 转为Number,首先使用a.valueOf()方法,返回[1] 
    // 继续调用toString方法,返回'1' 
    // 再将字符串转为数字1
    console.log(Number(a)); // 1
    // 如果重写valueOf方法,则会返回超乎想象的结果
    a.valueOf = () => {return 2};
    console.log(Number(a)); // 2
    

    1.3 toBoolean

    boolean类型转换过程只会进行真假值的检查,其中假值包括: false, '', null, undefined, NaN, +0, -0,假值将会转换为false,假值以外的其他值均为真值,转换为true

    console.log(Boolean(false)); // false
    console.log(Boolean('')); // false
    console.log(Boolean(null)); // false
    console.log(Boolean(undefined)); // false
    console.log(Boolean(NaN)); // false
    console.log(Boolean(+0)); // false
    console.log(Boolean(-0)); // false
    

    1.4 特殊

    对于一个特殊的对象Object.create(null),由于原型链的继承关系,该对象不继承Object,所以不存在valueOftoString方法,那么在进行转换的时候将抛出异常

    var a = Object.create(null);
    console.log(Number(a)); // Uncaught TypeError: Cannot convert object to primitive value
    

    2. 类型转换

    类型转换可以分为显示类型转换和隐式类型转换,但显示和隐式只是相对的,在我们知道会进行转换的时候他就是隐式,当我们知道会进行转换以后其实就变为了显式转换了。

    2.1 显示类型转换

    2.1.1 String()和Number()转换

    按照 1. 基本类型转换 的toString和toNumber的规则进行转换

    2.1.2 一元运算符转换

    使用一元运算符(+, -)会将数据转换为number类型,相当于Number(data)

    console.log(+[]); // 0 ,使用toNumber的规则,相当于Number([])
    
    2.1.3 位反运算符转换

    使用位反运算符(~)会将数据转换为number类型,相当于-(Number(data) + 1)

    console.log(~[]); // -1
    

    利用位反运算符,可以一些特定方法返回值进行处理后,简化判断

    // 例如indexOf匹配失败会返回-1,就可以利用位反运算简化判断条件
    if('abc'.indexOf('a') > -1) {}
    // 相当于
    if(~'abc'.indexOf('a')){}
    
    2.1.4 字符串解析

    使用parseIntparseFloat可以将字符串(非字符串会优先转换为字符串)解析为number类型,不同于Number()的强制类型转换,解析过程会进行到不能解析为止,而Number()转换在判断不能转换到时候直接返回NaN

    console.log(parseInt('12ab')); // 12
    console.log(Number('12ab')); // NaN
    

    在ES5以后,parseInt默认使用了10进制作为基数进行转换,可以通过第二个参数指定基数,此时对字符串解析过程会按照指定进制进行

    console.log(parseInt('1a', 19)); // 29 因为按照19进制1和a都是有效的字符,返回结果为29
    
    2.1.5 !转换

    使用'!',可以转换为boolean类型,转换相当于Boolean(data)

    console.log(!0); // true
    console.log(!!0); //false
    
    2.1.6 Symbol()对象转换

    Symbol对象不能通过隐式转换进行,如果要进行转换必须使用构造方法来显示转换(似乎只能转为字符串)。

    var a = Symbol('1');
    console.log(a + 1); Uncaught TypeError: Cannot convert a Symbol value to a number
    console.log(String(a) + 1); // 'Symbol(1)1'
    

    2.2 隐式类型转换

    2.2.1 算数运算转换

    在算数运算的过程中会进行数据转换:
    对于+运算来说,如果两个操作数中存在字符串,则会尝试进行字符串连接操作,如果操作数为对象,则会使用toPrimitive(使用valueOf方法和toString方法)转为基本类型后,再进行判断。如果不存在字符串,则全部转为数字进行加法操作。

    console.log(1 + ['1']); // 11 , 先将对象['1']根据toPrimitive规则转为'1',操作变为 1 + '1' , 进行字符串拼接
    

    对于-运算来说,直接将所有操作数进行toNumber操作后进行计算

    console.log(1 - ['1']); // 0
    
    2.2.2 逻辑语句中的类型转换

    作为逻辑语句中的判断条件,将转换为boolean值进行处理

    if(1) { console.log(1)}; //  由于Boolean(1)是true,所以会打印1
    if(0) { console.log(1)}; //  由于Boolean(0)是false,所以不会打印1
    
    2.2.3 ||和&&

    ||&&的操作,返回结果并不是boolean值,而是根据短路规则,判断操作数的Boolean()结果,返回两个操作数的其中之一,其中||true时进行短路返回,&&false时进行短路返回

    var a = 1 && 0;
    console.log(a); // 0 , 由于第一个操作数Boolean(1)是true,所以返回第二个操作数
    a = 0 && 1; 
    console.log(a); // 0 , 由于第一个操作数Boolean(0)是false,所以返回第一个操作数
    a = 1 || 0; 
    console.log(a); // 1, 由于第一个操作数Boolean(1)是true,所以返回第一个操作数
    a = 0 || 1; 
    console.log(a); // 1, 由于第一个操作数Boolean(0)是false,所以返回第二个操作数
    

    3. 数据比较

    3.1 宽松等于

    使用==进行比较的称做宽松等于,区别于===的严格等于,在于进行比较的时候,等式两边的数值在类型不相等的时候会尝试进行强制转换,而严格等于不会进行类型的转换。
    宽松等于的转化规则如下:

    • 如果两个比较数类型一致且为基本类型,则直接进行比较,数字按照大小,字符串按照字母表顺序比较。
    • 如果两个比较数类型不一致且为基本类型,则转换为number进行比较。
    • 如果两个比较数据均为对象类型,则比较对象的引用是否相等
    • 如果两个数据中一个为对象,则根据toPrimitive规则,将其转换为基本类型后,进行比较。

    console.log('a' == 'a'); // true , 类型相同且为基本类型,则直接比较
    console.log('1' == 1); // true , 类型不同但均为基本类型,将'1'转为number进行比较
    console.log({} == {}); // false , 两个比较数均为对象,判断引用是否相等
    console.log('a' == ['a']); // true,一个比较数为对象,则将['a']转换为'a'后进行比较
    

    对于特殊的undefinednull

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

    3.2 抽象比较

    抽象比较也就是非等于比较,比较规则和宽松等于规则相同

    console.log('a' < 'b'); // true, 类型相同,直接进行比较,字符串按照字母表顺序
    console.log('0' < 1); // true, 类型不同但均未基本类型,将'0'转为number后进行比较
    console.log('a' < ['b']); // true, 一个比较数为对象,则将['b']转换为'b'后进行比较
    

    4. 参考

    《你不知道的Javascript(中卷)》

    相关文章

      网友评论

          本文标题:Javascript学习笔记-强制类型转换

          本文链接:https://www.haomeiwen.com/subject/khcgjxtx.html