Js之类型转换

最近在看冴羽的博客,发现东西太多,也难记。所以还是决定照着过一遍,加深印象,也便于以后查阅。
原文请看:冴羽的博客
接下来进入正题,先是基本类型之间的转换:

js数据类型可以分为两类:
可变的引用类型: object(array ,function,正则);
不可变的原始类型: null, undefined, number, string, boolean, symbol(es6)

一、原始类型的转换

1.1 原始值转布尔

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

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

1.2 原始值转数字

Number()
我们可以使用 Number 函数将类型转换成数字类型,如果参数无法被转换为数字,则返回 NaN。
在这里插入图片描述
根据规范(上图),如果 Number 函数不传参数,返回 +0,如果有参数,调用 ToNumber(value)
注意这个 ToNumber 表示的是一个底层规范实现上的方法,并没有直接暴露出来。

ToNumber 则直接给了一个对应的结果表。表如下:
在这里插入图片描述

console.log(Number()) // +0

console.log(Number(undefined)) // NaN
console.log(Number(null)) // +0

console.log(Number(false)) // +0
console.log(Number(true)) // 1

console.log(Number("123")) // 123
console.log(Number("-123")) // -123
console.log(Number("1.2")) // 1.2
console.log(Number("000123")) // 123
console.log(Number("-000123")) // -123

console.log(Number("0x11")) // 17

console.log(Number("")) // 0
console.log(Number(" ")) // 0

console.log(Number("123 123")) // NaN
console.log(Number("foo")) // NaN
console.log(Number("100a")) // NaN

Number传入一个字符串,如果有一个字符不是数字,结果就会返回NaN;我们还会使用更加灵活的parseInt和parseFloat。
parseInt只解析整数,parseFloat可以解析整数和浮点数;
parseInt 和 parseFloat 都会跳过任意数量的前导空格,尽可能解析更多数值字符,并忽略后面的内容。如果第一个非空格字符是非法的数字直接量,将最终返回 NaN:

console.log(parseInt("3 abc")) // 3
console.log(parseFloat("3.14 abc")) // 3.14
console.log(parseInt("-12.34")) // -12
console.log(parseInt("0xFF")) // 255
console.log(parseFloat(".1")) // 0.1
console.log(parseInt("0.1")) // 0

1.3 原始值转字符

我们使用 String 函数将类型转换成字符串类型,依然先看 规范15.5.1.1中有关 String 函数的介绍:
在这里插入图片描述
如果 String 函数不传参数,返回空字符串,如果有参数,调用 ToString(value),而 ToString 也给了一个对应的结果表。表如下:
在这里插入图片描述

console.log(String()) // 空字符串

console.log(String(undefined)) // undefined
console.log(String(null)) // null

console.log(String(false)) // false
console.log(String(true)) // true

console.log(String(0)) // 0
console.log(String(-0)) // 0
console.log(String(NaN)) // NaN
console.log(String(Infinity)) // Infinity
console.log(String(-Infinity)) // -Infinity
console.log(String(1)) // 1

注意这里的 ToString 和上一节的 ToNumber 都是底层规范实现的方法,并没有直接暴露出来。

1.4 原始值转对象

原始值到对象的转换非常简单,原始值通过调用 String()、Number() 或者 Boolean() 构造函数,转换为它们各自的包装对象。
null 和 undefined 属于例外,当将它们用在期望是一个对象的地方都会造成一个类型错误 (TypeError) 异常,而不会执行正常的转换。

var a = 1;
console.log(typeof a); // number
var b = new Number(a);
console.log(typeof b); // object

二、引用类型的转换

2.1 对象转布尔值

对象到布尔值的转换非常简单:所有对象(包括数组和函数)都转换为 true。对于包装对象也是这样,举个例子:

console.log(Boolean(new Boolean(false))) // true

2.2.1对象转字符串和数字

对象到字符串和对象到数字的转换都是通过调用待转换对象的一个方法来完成的。而 JavaScript 对象有两个不同的方法来执行转换,一个是 toString,一个是 valueOf。注意这个跟上面所说的 ToString 和 ToNumber 是不同的,这两个方法是真实暴露出来的方法。

toString():
所有的对象除了 null 和 undefined 之外的任何值都具有 toString 方法;
通常情况下,它和使用 String 方法返回的结果一致。toString 方法的作用在于返回一个反映这个对象的字符串,然而这才是情况复杂的开始。

Object.prototype.toString.call({a: 1}) // "[object Object]"
({a: 1}).toString() // "[object Object]"
({a: 1}).toString === Object.prototype.toString // true

我们可以看出当调用对象的 toString 方法时,其实调用的是 Object.prototype 上的 toString 方法。

然而 JavaScript 下的很多类根据各自的特点,定义了更多版本的 toString 方法。例如:

  1. 数组的 toString 方法将每个数组元素转换成一个字符串,并在元素之间添加逗号后合并成结果字符串。
  2. 函数的 toString 方法返回源代码字符串。
  3. 日期的 toString 方法返回一个可读的日期和时间字符串。
  4. RegExp 的 toString 方法返回一个表示正则表达式直接量的字符串。
console.log(({}).toString()) // [object Object]

console.log([].toString()) // ""
console.log([0].toString()) // 0
console.log([1, 2, 3].toString()) // 1,2,3
console.log((function(){var a = 1;}).toString()) // function (){var a = 1;}
console.log((/\d+/g).toString()) // /\d+/g
console.log((new Date(2010, 0, 1)).toString()) // Fri Jan 01 2010 00:00:00 GMT+0800 (CST)

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

var arr = [1,2,3]
console.log(arr.valueOf()) //[1, 2, 3]
var date = new Date(2017, 4, 21);
console.log(date.valueOf()) // 1495296000000

2.2.2对象接着转字符串和数字

了解了 toString 方法和 valueOf 方法,我们分析下从对象到字符串是如何转换的。看规范 ES5 9.8,其实就是 ToString (value)方法的对应表,只是这次我们加上 Object 的转换规则:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
所谓的 ToPrimitive 方法,其实就是输入一个值,然后返回一个一定是基本类型的值。我们总结一下,当我们用 String 方法转化一个值的时候:

  1. 如果是基本类型,就参照 “原始值转字符” 这一节的对应表;
  2. 如果不是基本类型,我们会将调用一个 ToPrimitive 方法,将其(对象)转为基本类型,然后再参照“原始值转字符” 这一节的对应表进行转换。

虽然转换成基本值都会使用 ToPrimitive 方法,但传参有不同,最后的处理也有不同,转字符串调用的是 ToString,转数字调用 ToNumber。

接下来让我看一下,ToPrimitive()是如何将对象转化为基本值类型的!

2.2.3 ToPrimitive

让我们看规范 9.1,函数语法表示如下:

//input 表示要处理的输入值
//PrefefrredType, 非必填,表示希望转换成的类型,有两个值可以选择, Number和String.
ToPrimitive(input[, PreferredType])

1.当不传入 PreferredType 指定装换类型时:
如果 input 是日期类型,相当于传入 String,否则,都相当于传入 Number;如果传入的 input 是 Undefined、Null、Boolean、Number、String 基本类型,直接返回该值。

2.ToPrimitive(obj, Number)时:

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

3.ToPrimitive(obj, String)时:
1.如果 obj为 基本类型,直接返回
2.否则,调用 toString 方法,如果返回一个原始值,则 JavaScript 将其返回。
3.否则,调用 valueOf 方法,如果返回一个原始值,则 JavaScript 将其返回。
4.否则,JavaScript 抛出一个类型错误异常。

2.2.4 对象转字符串

所以总结下,对象转字符串可以概括为:

如果对象具有 toString 方法,则调用这个方法。如果他返回一个原始值,JavaScript 将这个值转换为字符串,并返回这个字符串结果。
如果对象没有 toString 方法,或者这个方法并不返回一个原始值,那么 JavaScript 会调用 valueOf 方法。如果存在这个方法,则 JavaScript 调用它。如果返回值是原始值,JavaScript 将这个值转换为字符串,并返回这个字符串的结果。
否则,JavaScript 无法从 toString 或者 valueOf 获得一个原始值,这时它将抛出一个类型错误异常。

2.2.5 对象转数字

对象转数字的过程中,JavaScript 做了同样的事情,只是它会首先尝试 valueOf 方法

如果对象具有 valueOf 方法,且返回一个原始值,则 JavaScript 将这个原始值转换为数字并返回这个数字
否则,如果对象具有 toString 方法,且返回一个原始值,则 JavaScript 将其转换并返回。
否则,JavaScript 抛出一个类型错误异常。

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

注意,在这个例子中,[] 和 [0] 都返回了 0,而 [1, 2, 3] 却返回了一个 NaN。我们分析一下原因:

当我们 Number([]) 的时候,先调用 [] 的 valueOf 方法,此时返回 [],因为返回了一个对象而不是原始值,所以又调用了 toString 方法,此时返回一个空字符串,接下来调用 ToNumber 这个规范上的方法,参照对应表,转换为 0, 所以最后的结果为 0。

而当我们 Number([1, 2, 3]) 的时候,先调用 [1, 2, 3] 的 valueOf 方法,此时返回 [1, 2, 3],再调用 toString 方法,此时返回 1,2,3,接下来调用 ToNumber,参照对应表,因为无法转换为数字,所以最后的结果为 NaN。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值