深度剖析JS类型转换规律(显示类型转换和隐式类型转换)

JavaScript的数据类型有number、string、boolean、undefined、null、object、function以及ES6新增的symbol,我们可以通过typeof运算符来查看变量的数据类型,如下:

typeof "Alice"                 // 返回 string
typeof 3.14                   // 返回 number
typeof NaN                    // 返回 number
typeof false                  // 返回 boolean
typeof [1,2,3,4]              // 返回 object
typeof {name:'Alice', age:12}  // 返回 object
typeof new Date()             // 返回 object
typeof function () {}         // 返回 function
typeof a                      // 返回 undefined (如果 a没有声明)
typeof null                   // 返回 object

注意:
NaN 的数据类型是 number
数组、日期对象、null的数据类型都是 object
未定义变量的数据类型为 undefined
因为普通对象和数组返回的类型都是object,所以我们得使用 constructor 属性来查看对象是否为数组 (包含字符串 "Array"):

function isArray(arr){
  return arr.constructor.tostring().indexof("Array")>-1;
}

同样判断是否是日期对象也可以使用constructor来查看:

function isDate(myDate) {
    return myDate.constructor.toString().indexOf("Date") > -1;
}

变量有数据类型,但并不是一成不变的,有的时候我们希望变量的数据类型发生变化,那么可以手动调用对应的JavaScript方法,有的时候 JavaScript 自身会自动的发生类型转换,我们把手动调用的称为显示类型转换,自动的称为隐式类型转换。

一、显示类型转换
显示类型转换是手动的调用对应的类型转换函数

  1. Number()
    千方百计将传入的数据转变成数字,转变不了也会将其变成NaN数字类型。注意:Number()不会截断数字
var num = Number("123") ;     // 返回 123
Number(true) ;                // 返回 1
Number(false) ;               // 返回 0
Number("true") ;               // 返回 NaN
Number("false") ;              // 返回 NaN
Number(null) ;                 // 返回 0
Number("null") ;               // 返回 NaN
Number(undefined) ;            // 返回 NaN
Number("123abc") ;             // 返回 NaN
Number("");                    // 返回 0 

若传入的类型是数值,转换后还是原来值
若传入的类型是字符串,且该字符串是数字字符串,则转换为对应数值;空字符串则转为0,其他类型字符串都为NaN
若传入的类型是布尔值,true为1,false为0
若传入的是undefined,结果为NaN
若传入的是null,返回0

  1. parseInt()

作用1:
用于将传入数据转变成整型

parseInt(null);//NaN
parseInt(true);//NaN
parseInt(false);//NaN
parseInt(undefined);//NaN

parseInt(123.9);//123 不会四舍五入 直接截断
parseInt("123abc");//123 从字符串首位开始到非字符串数字截断

parseInt不会管那么多,非数字只会转成数字类型,值为NaN
带小数数字直接截断,不会四舍五入
字符串数字或者开头为数值字符串的,从字符串首位开始到非字符串数字截断

作用2:
当传入两个参数时parseInt(num,radix),表示以radix进制为基底,将radix进制的num转成10进制
比如:

var num=10101010;
var temp = parseInt(num,2)

以上是将2进制的数num,转成10进制

  1. parseFloat(s)
    作用:用于将传入数据转变成浮点型,作用跟parseInt(s)相似,只是它带小数了:
parseFloat(null);//NaN
parseFloat(true);//NaN
parseFloat(false);//NaN
parseFloat(undefined);//NaN

parseFloat(123.9);//123.9
parseInt("123.1abc");//123.1

若字符串前几位是数字,它会检测到第一个小数点后的非数字字符串截断,若有第二个小数点,就到第二小数点前截断。

  1. toString()
    作用1:转成字符串
    作用2:将10进制的数据,转成任意进制。如 toString(16)
var a =15;
a.toString();//"15"
a.toString(16);//f

所以我们可以通过parseInt(num,某进制)转成10进制,通过.toString(任意进制)将数字转成任意进制,实现进制之间的转换。

  1. String(val)
    作用:将任意类型数据转换为字符串
    数值变成数字字符串
    字符串任是字符串
    布尔值true为”true”,false为”false”
    undefined、null变成对应的字符串“undefined”和“null”
  2. Boolean()
    转换为布尔型的值
    被认为是false的有:undefined、null、0、NaN、""空字符串
Boolean(undefined);//false
Boolean(null);//false
Boolean(-0);//false
Boolean(0);//false
Boolean(+0);//false
Boolean(NaN);//false
Boolean("");//false

二、隐式类型转换
有的时候js会偷偷的进行类型转换,转换了也没有告知我们,我们把这种称之为隐式类型转换。隐式类型转换内部也是调用显示的方法。

  1. 加号
    (1) 数字+任意类型
<script>
1+1;//2
1+null;//1
1+undefined;//NaN
1+true;//2
1+false;//1
1+"";//"1"
1+[];//"1"
1+[2];//"12"
1+[2,3];//"12,3"
1+{};//"1[object Object]"
1+{a:1,b:2};//"1[object Object]"
</script>

规律:

  • 数字+数字:直接相加
  • 数字+字符串:调用的是String();最终都为字符串
  • 数字+null:调用的Number();Number(null)为0
  • 数字+undefined:调用Number();Number(undefined)为NaN
  • 数字+布尔值:调用的Number();Number(true)为1,Number(false)为0
  • 数字+数组:调用的是String();String([])为"",String([2,3])为"2,3"
  • 数字+对象:调用的也是String();String({})为[object Object]

(2) 字符串+任意类型

<script>
"1"+1;//"11"
"1"+null;//"1null"
"1"+undefined;//"1undefined"
"1"+true;//"1true"
"1"+false;//"1false"
"1"+"";//"1"
"1"+[];//"1"
"1"+[2];//"12"
"1"+[2,3];//"12,3"
"1"+{};//"1[object Object]"
"1"+{a:1,b:2};//"1[object Object]"
</script>

记住一条规律:任何类型加字符串都得字符串。

(3) 布尔值+任意类型
上面两种情况有包含到两个规律:

  • 布尔值+数字,调用的Number(),
  • 布尔值+字符串,调用的是String()
    再来看布尔值+其他类型的情况
true + false;//1
true + null;//1
true + undefined;//NaN
true + [];//"true"
true + {};//"true[object Object]"
  • 布尔值+布尔值,调用的Number()
  • 布尔值+null,调用的Number()
  • 布尔值+undefined,调用的Number()
  • 布尔值+数组,调用的是String()
  • 布尔值+对象,调用的也是String();String({})为[object Object]

(4)null+任意类型
根据上面情况我们可以得出以下规律:

  • null+数字,调用的Number()
  • null+布尔值串,调用的是Number()
  • null+字符串,调用的是String()

再来看看其他情况

null + null;//0
null + undefined;//NaN
null + [];//"null"
null + {};//"null[object Object]"
  • null+null,调用的Number()
  • null+undefined,调用的是Number()
  • null+数组,调用的是String()
  • null+对象,调用的是String()

(5) undefined+任意类型
根据上面情况我们可以得出以下规律:

  • undefined+数字,调用的Number(),值为NaN
  • undefined+布尔值串,调用的是Number(),值为NaN
  • undefined+null,调用的是Number(),值为NaN
  • undefined+字符串,调用的是String()
undefined + undefined;//NaN
undefined + [];//"undefined"
undefined + {};//"undefined[object Object]"
  • undefined+undefined,调用的是Number()
  • undefined+数组,调用的是String()
  • undefined+对象,调用的是String()

(6) 数组+任意类型
规律:都调用的是String()

  • []+数字,调用的String()
  • []+布尔值串,调用的String()
  • []+null,调用的String()
  • []+字符串,调用的是String()
  • []+undefined,调用的String()
  • []+[],调用的是String()
  • []+{},调用的是String();
    特别注意[]+{}为"[object Object]",但是{}+[]为0

(7) 对象+任意类型
规律:
对象+任意类型除数组,都是调用String()
对象+数组时,比较奇怪:比如{}+[]为0,调用的既不是String也不是Number(),因为它返回的是0,按道理是Number,但是Number({})的值是NaN,我继续来看:

{}+[];//0
{a:1}+[];//0
{a:1}+[12];//12
{a:1}+[12,1];//NaN

经过观察,我们初步可以发现一个规律:当对象+数组时,返回的就是Number(数组)的值。有待进一步验证。

(8) function类型+任意类型
调用的是String()

  1. 减号、乘号、除号、取余
    调用的都是Number()
  2. ++ -- 一元正负
    调用的都是Number()
  3. isNaN()
    查看一个数是否是NaN,内部调用的是Number()
  4. if(表达式)
    表达式里面经常会放逻辑运算符&& || !,但最终会把表达式的结果运算出来,通过Boolean()转换成true/false
  5. 比较运算符也存在类型转换
<小于  
>大于
<=小于等于
>=大于等于
==等于
!=不等于

比较最终会变成布尔值,但是过程中会存在类型转换
规则:

  • 数与数比较,比较的是数值大小
  • 仅一个是数字,调用Number将另外一个变成数字,在进行数值比较
  • 字符串与其他非数值数字比较,将另外一个通过String()变成字符串,比较逐位的ASCII码
  • 两个中任意一个既不是数字也不是字符串,将两个比较对象转成数字或者字符串,再进行比较。
  • 无法转成字符串或数字,返回false
  • 与NaN比较,返回false
true > false;//true
100>10>0;//true
100>10>1;//false
null>0;//false
null<0;//false
null==0;//false
undefined>0;//false
undefined<0;//false
undefined==0;//false
null==undefined;//true
  1. 也存在不发生类型转换的,比如:
    ===绝对等于
    !==绝对不等于
1 === "1";//false
1 === true;//false
null === undefined;//false

参考资料
https://www.runoob.com/js/js-type-conversion.html
https://blog.csdn.net/q535999731/article/details/79643665
http://c.biancheng.net/view/5445.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335