JavaScript的强制类型转换

强制类型转换

将javascript的值从一种类型转换为另一种类型的值——>类型转换
隐式类型转换——>强制类型转换【返回总是基本类型值,string,number,boolean】。Toprimitive是转原始值,是供javascript内部使用的“抽象操作”。

ToString

对于普通对象,除非自定义toString()方法,否则toString方法返回的是内部属性[[Class]]【Object.prototype.toString()】。
数组默认的toString()方法是经过重新定义的

var a = [1,2,3];
a.toString();   //"1,2,3"
JSON.stringify()序列化

所有安全的JSON值都可以使用JSON.stringify进行字符串化。不安全的JSON值有:undefined,function,symbol。

JSON.stringify(undefined)    //undefined
JSON.stringify(function(){})    //undefined
JSON.stringify(Symbol())    //undefined
JSON.stringify([1,undefined,function(){},4])   //"[1,null,null,4]"

其实JSON.stringify序列化对象时,调用的是对象toJSON方法返回的对象。toJSON返回的是一个能够被字符串化的安全的JSON值。
JSON.stringify(obj,replacer,space);
replacer是个函数或者和数组,用于指定对象序列化过程中的数据过滤,类似toJSON。space则是缩进。

ToNumber

true->1,false->0,undefined->NaN,null->0
对象(包括数组)转数字,会先转成相应基本类型值,抽象操作ToPrimitive检查该值有没有valueOf()方法,如果没有就用toString()方法进行强制类型转换,两个方法都么有,会抛出错误【这种情况可以参考用Object.create(null)创建一个没有原型集成的对象,是无法进行强制类型转换的】。

JSON.stringify(Object.create(null))      //"{}"
Number(Object.create(null))   //报错:Cannot convert object to primitive value
String(Object.create(null))  //报错:Cannot convert object to primitive value
Boolean(Object.create(null))  //true(因为{}不在假值列表里面)

但是妥妥的打脸了!!!不晓得是不是浏览器做了专门的边界处理?

ToBoolean

Javascript中的假值:undefined,null,false,+0,-0和NaN,还有空字符串""。假值的强制转换类型为false,假值列表意以外的值都是真值(当然也包括假值的封装对象了):

var a = new Boolean(false);
var b = new Boolean(0);
var c = new Boolean('');
var d = Boolean(a && b && c)   ///true

所有的字符串都是真值,除了''空字符串外,因为它是假值列表中唯一的字符串。

var a = [];
var b = {};
var c = function(){};
var d = Boolean(a && b && c);  //d

因为[],{},function(){}都不在假值列表中,所以都是真值【真值列表无限长】

ToPrimitive(data,preferedType)【转换为原始值】

1.如果data是原始值,直接返回
2.否则,如果是对象,调用valueOf()返回原始值
3.否则,调用data.toString()返回原始值
4.否则,报错。

String() 和 new String(),Number() 和new Number()

String()转换遵循ToSting的规则,Number遵循ToNumber规则。字符串的转换还可以直接使用toString()方法。number的转换可以使用一元形式:

var c = "3.14";
var d = 5+ +c;
 d      //8.14
1 + - + + + - + 1;  //2(+只是转换为数字类型,-则即转换为数字类型,而且加了符号-)

一元运算符的常见装13用法:

//将Date对象强制转换为时间戳,以毫秒为单位
var d = new Date();
+d;   //1552902330544
var timestamp = +new Date();
//又或者,可以不用带括号(某些特殊没有参数的函数可以酱紫用)
var timestamp = + new Date;

其实获取当前时间还有其他方法:

var timestamp = new Date().getTime();  //最常用的
var timestamp = Date.now();   //ES5加入的

还有另外一个~运算符(按位非),就是二进制的按位非运算:
:返回2的补码。x => -(x+1),十进制的按位或就是==>加一取反。

var a = 'Hello World';
~a.indexOf('lo');   //-4   ==>真值
~a.indexOf('ol');   //0  ===>假值

以后判断字符串存在否,可以使用~indexOf()来判断了!!!

解析数字字符串

Number()和parseInt(),前者是转换,后者是解析。转换【不允许含有非数字字符串】和解析【允许含有非数字字符串】不是互相替代关系。

var a = "32";
var b = "32px";
Number(a)  //32
Number(b)  //NaN
parseInt(a)  //32
parseInt(b)  //32
解析非字符串
parseInt(1/0,19);   //18
//类似于
parseInt("Infinity",19);   //18
parseInt(new String(42))   //42
显示转换为布尔值Boolean()

一元运算符!显示将值强制转换为布尔值,所以显示转换为布尔值可以用!!。当然也可以使用Boolean()构造函数。

隐式强制类型转换

有人说是JavaScript的设计缺陷,但是它的作用是减少冗余,让代码更简洁。

var a = [1,2];
var b = [3,4]
a + b;   //"1,23,4"   "1,2"+"3,4" = "1,23,4"

a和b都是先转换为字符串后进行拼接。如果+操作是字符串,则执行字符串拼接,否则执行数字加法

[] + {}  //"[object Object]"
'' + {}  //"[object Object]"
{} + []  //0

因为String([]) //"";而String({}) //"[object Object]";Number([]) //0
而{} + [] //{}会被看成一个代码块,而不是一个js对象,+[]就是将[]转换为number,得出0的结果。

隐式转换作用

  • 将数字转换为字符串
var a = 42;
var b = a + ""; //"42"
  • 字符串强制转换为数字类型
var a = "3.14";
var b = a - 0; //3.14

因为-是数字减法运算符。类似还有a*1,a/1等将字符串转换为数字类型。

var a = [3];
var b = [1];
a - b; //2 

上面是先对两个数组进行字符串处理a = '3',b = '1',然后字符串用-时,进行数字转换运算。3 - 1 = 2。
b = String(a) //强制显示转换
b = a + "" //隐式类型转换
下面来个判断函数多个参数时,只有一个参数为真的情况返回true。

function onlyOne(){
   var sum = 0;
    for(var i = 0;i<arguments.length;i++){
        sum += Number(!!arguments[i]);
    }
    return sum === 1;
}

!!arguments[i] //将参数转换为true或者false。

  • 隐式转换为布尔值
    (1) if (..) 语句中的条件判断表达式。
    (2) for ( .. ; .. ; .. ) 语句中的条件判断表达式(第二个)。
    (3) while (..) 和do..while(..) 循环中的条件判断表达式。
    (4) ? : 中的条件判断表达式。
    (5) 逻辑运算符||(逻辑或)和&&(逻辑与)左边的操作数(作为条件判断表达式)。
    条件判断中的判断表达式。遵循ToBoolean规则。
  • || 和 &&
    他们的返回值是两个操作数中的一个(有且仅有一个)。
var a = 32;
var b = 'abc';
var c = null;
a || b;   // 32
a && b;  // "abc"
c || b    //"abc"
c && b  //null

可以看出,||和&&操作符都是首先对一个数进行条件判断,对于||来说,第一个数是true就返回第一个数,而&&条件判断,第一个数是false直接返回第一个数,否则返回第二个数。
可以称呼他们为“操作数选择器”。

a || b   ===  a ? a : b
a && b === a ? b : a

&&的妙用

function foo(){
  console.log(a)
}
var a = 42;
//短路机制
a && foo();  
//其所用相当于
if(a){
  foo();
}
  • 符号的强制类型转换
var s1 = Symbol('cool');
String(s1)    //"Symbol(cool)"
var s2 = Symbol("not cool");
s2 + "";   //TypeError
!!s1      //true

符号不能被强制转换为数字,但可以强制转换为布尔值,结果都是true。

宽松相等==和严格相等

解释一:“==检查值是否相等,===检查值和类型是否相等。这样子的描述仍然是不准确的!”
解释二:==允许在相等比较中进行强制类型转换,而===则不允许
解释一中可以看出===干的活似乎更多些,不止要检查类型还要检查值,解释二中==似乎干的活多些,因为如果类型不同,需要进行强制类型转换。
JavaScript引擎针对类型转换时间是微秒级的,可以不用在乎性能。所以:==和===都会检查数据类型,区别在于操作数据类型的处理方式不同,解释二是正确的,而解释一是不准确的。
而在比较对象相等时,==和===是一样的。

var a = 42;
var b = "42";
a === b //false
a == b //true,b会被转换为number类型进行比较
var a = "42";
var b = true;
 a  == b;  //false  ===> 42 == 1

遇到有布尔类型的宽松相等,还是都强制转换为数字进行对比。
任何情况下都不要使用==true和==false
而且在==宽松相等中,null和undefined是一回事呢!
null == undefined; //true
对象和非对象之间的==比较
都是将对象ToPromitive化【先调用对象的valueOf(),其默认返回的还是对象本身[捂脸],如果没有则调用对象的toString()】,然后再进行比较。

var a = 42;
var b = [ 42 ];
a == b;    // true

宽松相等==》null和undefined宽松相等,就是一回事,与其他任何值都不宽松相等;布尔值和其他类型比较,布尔先转化为数字后进行比较;字符串和数字比较,统一转化为数字进行比较;对象和非对象之间宽松相等比较,将对象toPrimitive后得到的基本类型,进行比较。

//对象的宽松相等,但是一般定义的对象,其valueOf返回的仍然是对象本身
var a = new String('123');
a == '123';  //true

看个比较奇怪的情况:

if(a == 2 && a == 3){
//...
}
var i = 2;
Number.prototype.valueOf = function(){
 i++;
}
var a = new Number(12);
if(a == 2 && a == 3){
  console.log("Yep, this happened.")
}
//Yep, this happened.

不常见的假值比较:

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

推荐阅读更多精彩内容