轻松玩转JS的类型转换(上)

将一种类型转换为另一种类型,便是类型转换,其中包括显示转换和隐式转换。
显示转换当然是用户自发调用API进行转换,隐式转换常常在我们意想不到的时候进行,当然,看完本篇博客,你就可以拥有洞察隐式转换的能力了。

在 JavaScript 中,当我们进行比较操作或者加减乘除四则运算操作时,常常会触发 JavaScript 的隐式类型转换机制;而这部分也往往是令人迷惑的地方。譬如浏览器中的 console.log 操作常常会将任何值都转化为字符串然后展示,而数学运算则会首先将值转化为数值类型(除了 Date 类型对象)然后进行操作。
比如:

console.log(1 + '1') //'11'
console.log(1 + []); //1

第一个将1转换成‘1’,然后和后边的字符串进行拼接,第二个的[]被转化成了0,那你可能会问,为什么第一个不转化’1’为1,然后1+1=2呢?当然主要是甲鱼的屁股——规定,官方是这么规定的,那我们必须遵守,当然你有能力可以自己创建自己的规范,然后自己造一个符合自己规范的语言,浏览器。。。话不多说,我们接下来会详细介绍背后的转化机制。

数据类型

我们知道JS的数据类型分为两类,一类是基本类型,一类是引用类型
JS有六大基本类型Number String Null Undefined Null Symbol
引用类型有:Object Array Function

因为下文表述有原始值和原始类型,我们约定 原始类型和基本类型等意

原始值转布尔

在 JavaScript 中,只有 6 种值可以被转换成 false,其他都会被转换成 true。


console.log(Boolean()); //false
console.log(Boolean(false)); //false

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

原始值转数值

类型转化后的结果
Number对应的数值
String较复杂,后边讨论
Booleantrue为1 ,false为0
UndefineNaN
Null+0

字符串转数字

我们先看几个例子

console.log(Number("123")); //123
console.log(Number("123aaa")); //NaN
console.log(Number('aaa123')); //NaN
console.log(Number('1 23')); //NaN
console.log(Number('1a23')); //NaN
console.log(Number('123   ')); //123
console.log(Number('    123')); //123
console.log(Number("000123")); //123
console.log(Number("0xff")); //255
console.log(Number(".123")); //0.123
console.log(Number("")) // 0
console.log(Number(" ")) // 0

我们可以发现几个规律

  1. 字符串中只有数字的话,那么就返回对应的数字值
  2. 只要字符串中,含有字母,以及数字之间有空格,就返回NaN
  3. 数字前后有空格,且没有字母包含在内,则返回对应数值
  4. 如果是按16进制形式书写,会自动转化成十进制
  5. 可以转化整数部分为0的小数。

基于这种严格判断,我们一般还是用parseInt或parseFloat进行更加灵活的转换。
parseInt 和 parseFloat 都会跳过任意数量的前导空格,尽可能解析更多数值字符,并忽略后面的内容。如果第一个非空格字符是非法的数字直接量,将最终返回 NaN:

console.log(parseInt("aaaa123")); //NaN
console.log(parseInt("123aaa")); //123
console.log(parseInt("     123")); //123

原始值转字符串

类型转化后的值
Boolean为 true 和 false对应单词的字符串
Undefined“undefined"
Null‘null’
String返回对应的字符串
Number也比较复杂,看例子
console.log(String(+0));//0
console.log(String(-0));//0
console.log(String(Infinity));//Infinity
console.log(String(-Infinity));//-Infinity

原始值转对象

这个很简单,每种类型都有对应的实例化方法。

console.log(typeof new Boolean(0)); //object
console.log(typeof false); //boolean
console.log(typeof new Number(1)); //object
console.log(typeof 1); //number
console.log(typeof new String('test')); //object
console.log(typeof 'test'); //number

null 和 undefined 属于例外,当将它们用在期望是一个对象的地方都会造成一个类型错误 (TypeError) 异常,而不会执行正常的转换。

对象转布尔

对象到布尔值的转换非常简单:所有对象(包括数组和函数)都转换为 true。

对象转字符串和数字

对象转字符串和数字,都是通过调用带转换对象的方法来进行转换的,有两个方法,toString 和 valueOf
我们知道Object.prototype,toString这个方法非常强大,他会返回[object 类名]字符串,经常用于我们的类型判断。

console.log(Object.prototype.toString({ a: 1 })); //'[object Object]'
{a: 1}).toString() // "[object Object]"

我们可以看做,在调用toString方法的时候,其实调用的是Object.prototype.toString()方法
当然js中也定义了很多版本的toString方法

  1. 数组的toString就是把数组里的每一个元素转化成字符串
  2. 函数的toString就是把整个函数体转化为字符串
  3. 日期的toString就是返回一个可读日期和时间字符串
  4. 正则的toString 就是返回对应正则表达式的字符串
console.log(['a,b'].toString()); //'a','b'
console.log([].toString()); //''
console.log((function() {}).toString()); //function(){}
console.log((new RegExp(/\d/)).toString()); //'/\d/'
console.log((new Date()).toString());//Fri Apr 24 2020 10:34:18 GMT+0800 (GMT+08:00)

默认的 valueOf 方法返回这个对象本身,数组、函数、正则简单的继承了这个默认方法,也会返回对象本身。日期是一个例外,它会返回它的一个内容表示: 1970 年 1 月 1 日以来的毫秒数。

接下来重头戏来了,我们了解了toString和valueOf之后,接下来了解对象转字符串和数字的内部机制是什么。

首先官方给的定义是,

类型结果
Object1. primValue = toPrimitive(input,number) 2. toNumber(primValue)
类型结果
Object1. primValue = toPrimitive(input,string) 2. toString(primValue)

所谓的 ToPrimitive 方法,其实就是输入一个值,然后返回一个一定是基本类型的值。

我们总结一下,当我们用 String 方法转化一个值的时候,如果是基本类型,就参照 “原始值转字符” 这一节的对应表,如果不是基本类型,我们会将调用一个 ToPrimitive 方法,将其转为基本类型,然后再参照“原始值转字符” 这一节的对应表进行转换。
转数字同理。

ToPrimitive

语法表示是

ToPrimitive(input[, PreferredType])
  1. input代表输入的内容,下一个参数是要转化成的类型
  2. 如果没有指定类型,那么除了input是日期是认为是字符串,其他都默认为数字类型
  3. 如果传入的 input 是 Undefined、Null、Boolean、Number、String 类型,直接返回该值。

ToPromitive(input,number)步骤如下:
4. input为基本类型,直接返回
5. 否则调用valueOf方法,如果返回一个原始值,则将其返回
6. 否则调用toString方法,如果返回一个原始值,则将其返回
7. 否则js抛出一个类型错误

ToPromitive(input,string)步骤如下:

  1. input为基本类型,直接返回
  2. 否则调用toString方法,如果返回一个原始值,则将其返回
  3. 否则调用valueOf方法,如果返回一个原始值,则将其返回
  4. 否则js抛出一个类型错误

依然是看几个例子

console.log(Number({})) // NaN
console.log(Number({a : 1})) // NaN

console.log(Number([])) // 0
console.log(Number([0])) // 0
console.log(Number([1, 2, 3])) // NaN
console.log(Number(function(){var a = 1;})) // NaN
console.log(Number(/\d+/g)) // NaN
console.log(Number(new Date(2010, 0, 1))) // 1262275200000
console.log(Number(new Error('a'))) // NaN

以第一个Number({})为例,{}不是基本类型,然后调用valueOf,返回{}本身,不是原始值,然后我们进行toString,返回‘[object Object]’,是一个字符串,然后按原始值转数字来转化,结果自然是NaN

我们再来分析Number([]),同样不是原始值,然后调用valueOf,返回[],然后调用toString,返回”“,依据原始值转数字,结果为0

其他例子读者可一次尝试。

JSON.stringify

这个方法就是将js值,转化为JSON串,其实也是调用了toString()方法,但是还是有一些区别。

  1. 处理原始值和toString的返回值相同
console.log(JSON.stringify(null)) // null
console.log(JSON.stringify(undefined)) // undefined,注意这个undefined不是字符串的undefined
console.log(JSON.stringify(undefined) == 'undefined');
console.log(JSON.stringify(true)) // true
console.log(JSON.stringify(42)) // 42
console.log(JSON.stringify("42")) // "42"
  1. 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
JSON.stringify([new Number(1), new String("false"), new Boolean(false)]); // "[1,"false",false]"
  1. undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。
JSON.stringify({x: undefined, y: Object, z: Symbol("")}); 
// "{}"

JSON.stringify([undefined, Object, Symbol("")]);          
// "[null,null,null]" 
  1. 如果一个被序列化的对象拥有 toJSON 方法,那么该 toJSON 方法就会覆盖该对象默认的序列化行为:不是那个对象被序列化,而是调用 toJSON 方法后的返回值会被序列化,例如:
var obj = {
  foo: 'foo',
  toJSON: function () {
    return 'bar';
  }
};
JSON.stringify(obj);      // '"bar"'
JSON.stringify({x: obj}); // '{"x":"bar"}'

当然,到这里,内部的转换机制我们基本了解了,但是关于类型转换还没完,我们先消化一下,然后转到这里
轻松玩转JS的类型转换(下)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值