详解JavaScript中的强制类型转换
avaScript原语
JavaScript建立在一系列基本单元之上。你应该对其中的一些已经很熟悉了,比如字符串和数字:
vargreet="Hello"; varyear=89;
字符串和数字是该语言所谓“原语”的一部分。完整清单是:
- String
- Number
- Boolean
- Null
- Undefined
- Object
- Symbol(ES6中添加,此处不予介绍)
布尔值用来表示可能是真或假的值。null是故意不去赋值,它通常被分配给一个变量,用于表示绑定完毕,稍后将填充有意义的内容。
varmaybe=null;
然后才是undefined,这意味着变量仍然没有被附加上:
varname; console.log(name) undefined
null和undefined看起来非常相似,但它们是两个截然不同的实体,很多开发人员仍然不确定应该使用哪个。
如果要判断JavaScript实例的类型,可以用typeof运算符。让我们用字符串尝试一下:
typeof"alex" >"string"
还有数字:
typeof9 >"number"
用于布尔值:
typeoffalse >"boolean"
undefined:
typeofundefined >"undefined"
还有null:
typeofnull >"object"
结果令人惊讶!null看起来像一个对象,但实际上它是JavaScript中的一个历史性错误,自语言诞生就躺在那里了。由于这些问题,JavaScript一直声名狼借。但这仅仅是个开始。
陌生的事情
在JavaScript中,在两种类型之间进行转换时有一些奇怪的规则。让我给你一些背景信息。先用Python举一个例子。在Python中执行以下指令:
'hello'+89
会给你一个明确的错误:
TypeError:canonlyconcatenatestr(**not**"int")tostr
而在JavaScript中,只有天空才是你的极限:
'hello'+89
事实上给出:
"hello89"
如果我们尝试向字符串添加数组,看起来会更加奇怪:
'hello'+[]
将会得到
'hello'
还有
'hello'+[89]
会给你一个惊喜:
"hello89"
看起来这种转换背后存在某种逻辑。它甚至适用于存在更多元素的array:
'hello'+[89,150.156,'mike']
得到:
"hello89,150.156,mike"
这两行JavaScript足以让Java程序员逃离。但是这种行为在JavaScript中100%是又意义的。因此这种隐式转换,也称为强制类型转换是非常值得探索的。
当一个数字变成一个字符串
一些编程语言有一个叫做类型转换的概念,这意味着:如果我想把一个数字或实例转换为另一种类型,那么我必须使显式转换。它也适用于JavaScript。请看以下示例:
vargreet="Hello"; varyear=89;
如果我想明确的进行转换,可以在代码中表明意图:
vargreet="Hello"; varyear=89; varyearString=year.toString()
要么这样做:
vargreet="Hello"; varyear=89; varyearString=String(year)
然后我可以连接两个变量:
greet+yearString;
但是在JavaScript中有一种被称为隐式转换的微妙机制,由JavaScript引擎提供。该语言不会阻止我们对数字和字符串进行加法操作:
'hello'+89
会得到:
"hello89"
但是这种转换背后的逻辑是什么?你可能会惊讶地发现JavaScript中的加法运算符+会自动将两个操作数中的任何一个都转换为字符串,如果其中至少有一个是字符串的话!
你会发现更令人惊讶的是,这条规则在ECMAScript规范中一脉相承。第11.6.1节定义了加法运算符的行为,我在这里为你做了总结:
如果x是String或y是String,则返回ToString(x),然后返回ToString(y)
这个花招只适用于数字吗?并不是。数组和对象也会受到相同的转换:
'hello'+[89,150.156,'mike']
会得到:
"hello89,150.156,mike"
那么下面的代码会得到怎样的结果:
'hello'+{name:"Jacopo"}
要找到答案,你可以通过将对象转换为字符串来进行快速测试:
String({name:"Jacopo"})
将会得到:
"[objectObject]"
所以我有一种感觉:
'hello'+{name:"Jacopo"}
会得到:
"hello[objectObject]"
打住!这又是什么?
JavaScript中[objectObject]的含义是什么?
“[objectObject]”是最常见的JavaScript“怪癖”之一。
几乎每个JavaScript实例都有一个名为toString()的方法,有些方法是由Object.prototype.toString提供的。
某些类型(如数组)实现了toString()的自定义版本,以便在调用方法时将值转换为字符串。例如Array.prototype.toString会覆盖Object.toString()(也称为methodshadowing)。
但是当你在普通的JavaScript对象上调用toString()时,引擎会给出“[objectObject]”,因为Object.toString()的默认行为是由实体类型(在这种情况下为Object)返回字符串object。
现在让我们把注意力集中在JavaScript比较运算符上,它们与算术运算符一样奇怪。
等于还是不等于?
JavaScript中有两个主要的比较运算符。
第一个我们称之为“弱比较”。这是抽象比较运算符(双等号):==。
另一个是“强比较”,可以通过三等号进行识别:===也称为严格比较运算符。它们两者的行为方式完全不同。
来看一些例子。首先,如果我们将两个字符串与两个运算符进行比较,我们得到相同的结果
"hello"=="hello"
>true
"hello"==="hello"
>true
看上去一切都还好。
现在尝试比较两种不同的类型,数字和字符串。首先是“强比较”:
"1"===1 false
这说得通!字符串“1”与数字1是不同的。但是“弱比较”会发生什么?
"1"==1 true
居然是true!它没有任何意义,除非这种行为与我们之前看到的隐式转换有关。
如果适用相同的规则怎么办?没错!ECMAScriptspec再次罢工。结果抽象比较运算符在比较它们之前在类型之间进行自动转换。这是规范的摘要:
比较x==y执行如下:
如果x是String且y是Number,则返回比较结果ToNumber(x)==y
规范说:如果第一个操作数是一个字符串,第二个操作数是一个数字,那么将第一个操作数转换为数字。有趣。
JavaScript规范充满了这个疯狂的规则,我强烈鼓励大家对它深入挖掘。
在此期间除非你有充分的理由否则在JavaScript代码中避免使用抽象比较运算符。你以后会感谢自己的。
那么“强势比较”怎么样?规范中的说严格相等比较在把值与三等===进行比较之前没有进行自动转换。在代码中使用严格相等比较可以避免愚蠢的bug。
总结
JavaScript中有七个构建块,即String,Number,Boolean,Null,Undefined,Object和Symbol。这些类型被称为基元。
JavaScript开发人员可以使用算术和比较运算符来操作这些类型。但是我们要特别注意加法运算符+和抽象比较运算符==,它本质上倾向于在类型之间进行转换。
以上所述是小编给大家介绍的JavaScript中的强制类型转换详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!