相信刚开始了解js的时候,都会遇到 2 =='2',但 1+2 == 1+'2'为false的状况。这时候应该会是一脸懵逼的状态,不得不感慨js弱类型的灵活让人发指,隐式类型转换就是这么猝不及防。结合实际中的状况来看,有意或无心中涉及到隐式类型转换的状况仍是不少的。既然要用到,就须要掌握其原理,知其然重要知其因此然更重要。git
JavaScript 是弱类型语言,意味着JavaScript 变量没有预先肯定的类型。
而且变量的类型是其值的类型。也就是说变量当前的类型由其值所决定,夸张点说上一秒种的string,下一秒可能就是个array了。此外当进行某些操做时,变量能够进行类型转换,咱们主动进行的就是显式类型转换,另外一种就是隐式类型转换了。例如:es6
var a = '1'; typeof a;//string a =parseInt(a); //显示转换为number typeof a //number a == '1' //true
弱类型的特性在给咱们带来便利的同时,也会给咱们带来困扰。趋利避害,充分利用该特性的前提就是掌握类型转换的原理,下面一块儿看一下。github
老生常谈的两大类数据类型:算法
此外还有一个es6新增的Symbol,先不讨论它。对于这五类原始类型,忽然提问可能想不全,不必去死记硬背,能够想一下为否的常见变量及其对应值便可。学习
0 | Number |
---|---|
'' | String |
false | Boolean |
null | Null |
undefined | Undefined |
对于不一样的数据格式转换规则是不一样的,咱们须要分别对待。this
既然是规范定义的规则,那就不要问为何了,先大体看一下,争取记住。是在不行常常翻翻看看大佬的博客es5规范。转换有下面这么几类,咱们分别看一下具体规范。(这部分转换规则,彻底能够跳过去,看到下面的实例再回头看应该更容易接受一些)es5
ToPrimitive 运算符接受一个值,和一个可选的 指望类型 做参数。ToPrimitive 运算符把其值参数转换为非对象类型。若是对象有能力被转换为不止一种原语类型,可使用可选的 指望类型 来暗示那个类型。根据下表完成转换 spa
这段定义看起来有点枯燥。转换为原始值,其实就是针对引用数据的,其目的是转换为非对象类型。
若是已是原始类型,固然就不作处理了
对于object,返回对应的原始类型,该原始类型是由指望类型决定的,指望类型其实就是咱们传递的type。直接看下面比较清楚。
ToPrimitive方法大概长这么个样子具体以下。3d
/** * @obj 须要转换的对象 * @type 指望转换为的原始数据类型,可选 */ ToPrimitive(obj,type)
type能够为number或者string,二者的执行顺序有一些差异
string:code
number:
其实就是调用方法前后,毕竟指望数据类型不一样,若是是string固然优先调用toString。反之亦然。
固然type参数能够为空,这时候type的默认值会按照下面的规则设置
对于Date数据类型,咱们更多指望得到的是其转为时间后的字符串,而非毫秒值,若是为number,则会取到对应的毫秒值,显然字符串使用更多。
其余类型对象按照取值的类型操做便可。
归纳而言,ToPrimitive转成何种原始类型,取决于type,type参数可选,若指定,则按照指定类型转换,若不指定,默认根据实用状况分两种状况,Date为string,其他对象为number。那么何时会指定type类型呢,那就要看下面两种转换方式了。
某些特定状况下须要用到ToNumber方法来转成number
运算符根据下表将其参数转换为数值类型的值
对于string类型,状况比较多,只要掌握常见的就好了。和直接调用Number(str)的结果一致,这里就很少提了,主要是太多提不完。
须要注意的是,这里调用ToPrimitive的时候,type就指定为number了。下面的toString则为string。
ToString 运算符根据下表将其参数转换为字符串类型的值:
其实了解也很简单,毕竟是个规范,借用大佬一张图:
虽然是须要死记的东西,仍是有些规律可循的。
对于原始值:
当调用 valueOf 方法,采用以下步骤:
不一样内置对象的valueOf实现:
对照代码更清晰一点
var str = new String('123') //123 console.log(str.valueOf()) var num = new Number(123) //123 console.log(num.valueOf()) var date = new Date() //1526990889729 console.log(date.valueOf()) var bool = new Boolean('123') //true console.log(bool.valueOf()) var obj = new Object({valueOf:()=>{ return 1 }}) //依赖于内部实现 console.log(obj.valueOf())
前面提了那么多抽象概念,就是为了这里来理解具体转换的。
对于+运算来讲,规则以下:
说的本身都迷糊了快,一块儿结合代码来看一下
1+'2'+false
咱们看一个复杂的
var obj1 = { valueOf:function(){ return 1 } } var obj2 = { toString:function(){ return 'a' } } //2 console.log(1+obj1) //1a console.log('1'+ obj2) //1a console.log(obj1+obj2)
无论多复杂,按照上面的顺序来吧。
1+obj1
1+obj2
obj1+obj2
到这里相信你们对+这种运算的类型转换了解的差很少了。下面就看一下另外一种隐式类型转换
这种比较分为两大类,
相同的就不说了,隐式转换发生在不一样类型之间。规律比较复杂,规范比较长,这里也不列举了,你们能够查看抽象相等算法。简单总结一句,相等比较就不想+运算那样string优先了,是以number优先级为最高。归纳而言就是,都尽可能转成number来进行处理,这样也能够理解,毕竟比较仍是指望比较数值。那么规则大概以下:
对于x == y
若是x,y均为number,直接比较
没什么可解释的了 1 == 2 //false
若是存在对象,ToPrimitive() type为number进行转换,再进行后面比较
var obj1 = { valueOf:function(){ return '1' } } 1 == obj2 //true //obj1转为原始值,调用obj1.valueOf() //返回原始值'1' //'1'toNumber获得 1 而后比较 1 == 1 [] == ![] //true //[]做为对象ToPrimitive获得 '' //![]做为boolean转换获得0 //'' == 0 //转换为 0==0 //true
存在boolean,按照ToNumber将boolean转换为1或者0,再进行后面比较
//boolean 先转成number,按照上面的规则获得1 //3 == 1 false //0 == 0 true 3 == true // false '0' == false //true
若是x为string,y为number,x转成number进行比较
//'0' toNumber()获得 0 //0 == 0 true '0' == 0 //true
ECMAScript5.1中文版 + ECMAScript3 + ECMAScript(合集)
你所忽略的js隐式转换
这篇文章的本意是为本身解惑,写到后面真的感受比较乏味,毕竟规范性的东西多一点,不过深刻了解一下总好过死记硬背。原文请移步个人博客。对于有些观点说这些属于js糟粕,彻底不该该深刻,怎么说呢,结合本身状况判断吧。本人水平有限,抛砖引玉共同窗习。