隐式转换的规则

问题:隐式转换的规则是什么

说起JS的隐式转换规则,我们可以说下JS的基础数据类型

JS的七中类型

我们所熟知的JS,可以在大体上可以分为2中类型:原始类型,复杂类型(对象类型)

原始类型

JS再继续细分的话,原始类型包含:stringnumberbooleannullundefinedsymbol

对象类型

JS的对象类型包含:object

三种隐式转换类型

JS中一个难点就是隐式转换,因为JS在一些操作符下其类型会做一些变化,所以JS灵活,同时也会造成一些错误,并且难以理解

这其中涉及隐式转换最多的两个运算符 + ==

+运算符即可数字相加,也可以字符串相加,所以比较麻烦,== 不同于 ===,也存在隐式转换, */-这些操作符都是针对number类型的,故转换的结果只能是转换成number

隐式转换中主要是三种转换方式:

  • 将值转换为原始值。toPrimitive(input,type?);
  • 将值转换为数字。toNumber()
  • 将值转换为字符串。toString()

通过toPrimitive()将值转换为原始值

ToPrimitive(input,PreferredType?)

input是要转换的值,Preferred是可选参数,可以是Number或者String类型。他只是一个转换标志。转换后的结果并不一定是这个参数所代表的类型,但是转换结果一定是个原始值或者是错误

ToPrimitive(input,number)

  • 如果输入的已经是一个原始值,则直接返回它,
  • 否则,如果输入的是一个对象,则使用这个对象上面的valueOf()方法。如果valueOf()返回的是一个原始值,则返回这个原始值
  • 否则,调用这个对象上面的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。
  • 否则,抛出一个typeError异常

ToPrimitive(input,string)

  • 如果输入的已经是一个原始值,则直接返回它。
  • 否则,如果输入的是一个对象,则使用这个对象上面的toString()方法。如果toString()返回的是一个原始值。则返回这个原始值
  • 否则,调用这个对象上面的vaueOf()方法,如果valueOf方法返回一个原始值,则直接返回
  • 否则,抛出typeError异常

既然第二个参数是可选的,那么如果我们不填写这个参数的话,怎么转换呢?

规则如下:
1、如果对象是Date,则第二个参数是string
2、否则是number

valueOf方法和toString方法解析

JS常见内置对象:DateArrayMathNumberBooleanStringRegExpFunction

1、NumberBooleanString 这三种构造函数生成的基础值的对象形式,通过valueOf转换后会变成相应的原始值。

比如:

var num = new Number('123')
num.valueOf(); // 123

var str = new String('12df');
str.valueOf(); // '12df'

var bool = new Boolean('fd');
bool.valueOf(); // true

2、Date这种特殊的对象,其原型Date.prototype上内置的valueOf函数是将日期转换为毫秒数的形式的值

var a = new Date();
a.valueOf(); // 1515143895500

3、除此之外返回的都是他们自己本身

var a = new Array();
a.valueOf() === a; // true

var b = new Object({});
b.valueOf() === b; // true

上面说了valueOf函数,下面说说toString函数

1、NumberBooleanStringArrayDateRegExpFunction这几种构造函数生成的对象,通过toString转换后会变成相应的字符串的形式,因为这些构造函数上封装了自己的toString方法

Number.prototype.hasOwnProperty('toString'); // true
Boolean.prototype.hasOwnProperty('toString'); // true
String.prototype.hasOwnProperty('toString'); // true
Array.prototype.hasOwnProperty('toString'); // true
Date.prototype.hasOwnProperty('toString'); // true
RegExp.prototype.hasOwnProperty('toString'); // true
Function.prototype.hasOwnProperty('toString'); // true

var num = new Number('123sd');
num.toString(); // 'NaN'

var str = new String('12df');
str.toString(); // '12df'

var bool = new Boolean('fd');
bool.toString(); // 'true'

var arr = new Array(1,2);
arr.toString(); // '1,2'

var d = new Date();
d.toString(); // "Wed Oct 11 2017 08:00:00 GMT+0800 (中国标准时间)"

var func = function () {}
func.toString(); // "function () {}"

除了这些对象及其实例化对象之外,其他的对象返回的都是该对象的类型。都是继承的Object.prototype.toString

var obj = new Object({})
obj.toString() // '[object object]'

Math.toString(); // "[object Math]"

从上面valueOftoString两个函数对对象的转换可以看出为什么对于ToPrimitive(input, PreferredType?)PreferredType没有设定的时候,除了Date类型,PreferredType被设置为String,其它的会设置成Number
因为valueOf函数会将NumberStringBoolean基础类型的对象类型值转换成 基础类型,Date类型转换为毫秒数,其它的返回对象本身,而toString方法会将所有对象转换为字符串。显然对于大部分对象转换,valueOf转换更合理些,因为并没有规定转换类型,应该尽可能保持原有值,而不应该想toString方法一样,一股脑将其转换为字符串。
所以对于没有指定PreferredType类型时,先进行valueOf方法转换更好,故将PreferredType设置为Number类型。
而对于Date类型,其进行valueOf转换为毫秒数的number类型。在进行隐式转换时,没有指定将其转换为number类型时,将其转换为那么大的number类型的值显然没有多大意义。(不管是在+运算符还是==运算符)还不如转换为字符串格式的日期,所以默认Date类型会优先进行toString转换。故有以上的规则:

总结

PreferredType没有设置时,Date类型的对象,PreferredType默认设置为String,其他类型对象PreferredType默认设置为Number

你可能感兴趣的:(隐式转换的规则)