做者:valentinogagliardihtml
译者:前端小智前端
来源:githubgit
阿里云最近在作活动,低至2折,有兴趣能够看看: promotion.aliyun.com/ntms/yunpar…es6
为了保证的可读性,本文采用意译而非直译。github
JS 有 7 种基本类型,分别以下:算法
布尔值表示的值能够是 true
,也能够是 false
。另外一方面,null
是故意缺乏一个值。null
一般被赋值给一个变量,用来表示变量事后会被赋予值。编程
var maybe = null;
复制代码
而后是 undefined
,表示是一个变量没有任何附加项:数组
var name;
console.log(name)
undefined
复制代码
null
和 undefined
看起来很类似,但它们是两个大相径庭的类型,以致于开发人员仍不肯定要使用哪一个类型。微信
可使用 typeof
操做符来查看变量的类型:编程语言
typeof "alex"
"string"
复制代码
number
类型:
typeof 9
"number"
复制代码
boolean
类型:
typeof false
"boolean"
复制代码
undefined
类型:
typeof undefined
"undefined"
复制代码
null
类型
typeof null
"object"
复制代码
这个结果有点奇怪。null
看起来像一个对象,但实际上它是JS的一个历史错误,自该语言诞生以来就一直存在。因为这些缘由,JS 一直名声不佳。null
只是其中的一例。另外,一种类型和另外一种类型之间的转换有一些奇怪的规则。
先给你们介绍一下背景。各位先用 Python 作一个例子。Python 中的如下指令
'hello' + 89
复制代码
这样会获得一个明确的错误:
TypeError: can only concatenate str (not "int") to str
复制代码
在 JS 中彻底没有问题:
'hello' + 89
复制代码
结果:
"hello89"
复制代码
更加奇怪是直接加一个数组:
'hello' + []
复制代码
结果:
'hello'
复制代码
再来:
'hello' + [89]
复制代码
结果:
"hello89"
复制代码
看起来这种转换背后有某种逻辑,甚至还能够有更加复杂的数组结构:
'hello' + [89, 150.156, 'mike']
复制代码
结果:
"hello89,150.156,mike"
复制代码
这两行 JS 足以让 Java 开发人员望而却步。可是 JS 中的这种行为是100%
故意的。所以,有必要研究一下 JS 中隐式转换(也称为类型强制转换)。
一些编程语言有一个称为类型转换的概念,这意味着:若是我们想将一个类型转换成另外一种类型,那么必须使转换明确。在 JS 中也有提供这种方法。考虑如下示例
var greet = "Hello";
var year = 89;
复制代码
若是想进行显式转换,能够在代码中用 toString()
方法:
var greet = "Hello";
var year = 89;
var yearString = year.toString()
复制代码
或者使用 String
:
var greet = "Hello";
var year = 89;
var yearString = String(year)
复制代码
String
是JS 内置对象的一部分,它反映了一些基本类型:String
、Number
、Boolean
和Object
。这些内置组件可用于类型之间的转换。转换后,我们能够拼接两个变量
greet + yearString;
复制代码
可是除了这种显式转换以外,在 JS 中还有一种微妙的机制,称为隐式转换,由 JS 引擎提供。
'hello' + 89
复制代码
结果:
"hello89"
复制代码
可是这种转换背后的逻辑是什么? 你可能会惊讶地发现,若是 JS 中的加法运算符+
中的一个是字符串,则会自动将两个操做数中的任何一个转换为字符串!
更使人惊讶的是,这个规则在ECMAScript规范中已经固定下来了。第11.6.1节定义了加法运算符的行为,在这里总结一下:
加法运算符(+) 若是 x 是字符串或者 y 是字符串那么返回 ToString(x) 后面跟 ToString(y)
这种把戏只对数字有效吗? 不是,数组和对象同样的,跑不掉:
'hello' + [89, 150.156, 'mike']
复制代码
结果:
"hello89,150.156,mike"
复制代码
对象怎样:
'hello' + { name: "Jacopo" }
复制代码
结果:
"hello[object Object]"
复制代码
为了弄清,咋肥事,能够经过将对象转换为字符串来进行快速测试:
String({ name: "Jacopo" })
复制代码
结果:
"[object, Object]"
复制代码
但还有另外一个问题:乘法、除法和减法的状况又是肿么样的?
我们看到加法运算符在至少一个操做数是字符串时,是如何将操做数转换成字符串。可是其余的算术运算符呢?
操做符 | 描述 |
---|---|
+ | 加 |
++ | 自增 |
* | 乘 |
** | 指数 (es6) |
- | 减 |
-- | 自减 |
/ | 除 |
% | 取余 |
若是对不是数字的类型使用其中一个操做符(+除外
),那么就获得了一种特殊类型的 : NaN
89 ** "alex"
复制代码
结果:
NaN
复制代码
NaN
表示不是数字,任何失败的算术运算,以下面的代码所示:
var obj = { name: "Jacopo" } % 508897
复制代码
结果:
console.log(obj)
NaN
复制代码
注意与NaN
结合的 typeof
。这个代码看起来没问题:
typeof 9 / "alex"
NaN
复制代码
那下面呢?
var strange = 9 / "alex"
复制代码
再使用 typeof
:
typeof strange
"number"
复制代码
当 NaN
被分配给一个变量时,它就变成了number
,这就引出了一个新问题。我如何检查一些变量是不是 NaN
? ES6 中有一个名为 isNaN()
的新方法:
var strange = 9 / "alex"
isNaN(strange)
true
复制代码
接着来看看 JS 中的比较运算符,它们和算术运算符同样奇怪。
JS 中有两大类比较运算符。首先是所说的**“弱比较”**。它是一个抽象的比较运算符(双等号):==
。而后还有一个“强比较”:===
,又名 严格比较运算符。他俩兄弟的行为方式不同,来看看一些例子。
首先,若是我们用两个操做符比较两个字符串,俩兄弟获得一致的结果:
"hello" == "hello"
true
"hello" === "hello"
true
复制代码
看起来很 nice,如今来比较两种不一样的类型,数字和字符串。
首先是“强比较”
"1" === 1
false
复制代码
很明显,字符串 1 等于数字 1。弱比较又是怎么样?
"1" == 1
true
复制代码
true
表示这两个值相等。这种行为与我们前面看到的隐式转换有关。原来,抽象比较操做符会在比较类型以前自动转换类型。这是一个摘要:
抽象等式比较算法 比较
x == y
是这样执行的:若是x
是字符串,y
是数字,返回比较的结果ToNumber(x) == y
说白了就是:若是第一个操做数是字符串,第二个操做数是数字,那么将第一个操做数转换为数字。
有趣的是,JS 规范中充满了这些疯狂的规则,我强烈建议对此进行更深刻的研究。固然如今都建议使用强比较。
严格相等比较的规范指出,在将值与===
进行比较以前,不会进行自动转换。在代码中使用严格的相等比较能够避免愚蠢的错误。
我们已经看到了 JS 的构建块:String
、Number
、Boolean
、Null、Undefined
、Object
和Symbol
。它们都是大写的,这种风格甚至出如今ECMAScript规范中。可是除了这些基本类型以外,还有一些镜像原语的双胞胎:内置对象。例如,String
类型有一个等效的 String
,它以两种方式使用。若是像函数那样调用(经过传递参数),它会将任何值转换成字符串:
var someValue = 555;
String(someValue);
"555"
复制代码
若是使用 String
做为 new
的构造函数,那么结果就是String
类型的对象
var someValue = 555;
var newString = new String(someValue);
复制代码
这种方式值得在控制台中查看对象,看看它与“普通”字符串有何不一样
可使用 typeof
来确认它确实是一个对象:
typeof newString
"object"
复制代码
基本类型的 Number 也有一个内置对象 Number
,它能够(几乎)将任何值转换为数字:
var someValue = "555";
Number(someValue);
555;
复制代码
我说的几乎是由于在试图转换无效的“数字”时获得 NaN
var notValidNumber = "aa555";
Number(notValidNumber);
NaN;
复制代码
在构造函数形式Number
中使用时,将返回number
类型的新对象:
var someValue = "555";
new Number(someValue);
Number {555}
复制代码
内置对象 Boolean
以将任何值转换成布尔值:
var convertMe = 'alex';
Boolean(convertMe)
true
复制代码
用构造函数的方式会返回一个对象:
var convertMe = 'alex';
typeof new Boolean(convertMe)
"object"
复制代码
内置的 Object
行为也同样:
Object('hello'); // String {"hello"}
Object(1); // Number{1}
复制代码
若是在没有参数的状况下调用,它将返回一个空对象
Object()
{}
复制代码
若是做为构造函数调用,则返回一个新对象
new Object({
name: "Alex",
age: 33
});
{name: "Alex", age: 33}
复制代码
此时,你可能会问本身:何时可使用内置对象,何时应该使用基本类型初始化值? 根据经验,当你只须要一个简单的类型时,应该避免构造函数调用:
// 不要这么用
var bool = new Boolean("alex");
var str = new String('hi');
var num = new Number(33);
var strObj = new Object('hello')
复制代码
除了不实用以外,这种形式还会带来性能损失,由于这种方式每次都会建立一个新对象。 最后但一样重要的是,当我们想要一个简单的字符串或数字时,建立一个对象是没有意义的。因此下面的形式是首选的
// ok 的
var bool = true
var str = 'hi';
var num = 33;
var obj = { name: "Alex", age: 33 };
复制代码
当须要转换某些内容时,能够像使用函数同样使用 Boolean
、String
和 Number
,。
JS 中有七个构建块,即 String
、Number
、Boolean
、Null
、Undefined
、Object
和Symbol
,这些也称为基本类型。
JS 开发人员可使用算术和比较操做符操做这些类型。可是我们须要特别注意加法运算符+
和抽象比较运算符 ==
,它们本质上倾向于在类型之间进行转换。
这种 JS 中的隐式转换称为类型强制转换,并在ECMAScript规范中定义。建议在代码中始终使用严格的比较操做符===
代替 ==
。
做为一种最佳实践,当你打算在一种类型和另外一种类型之间进行转换时,必定要弄清楚彼此之间的类型。为此,JS 有一堆内建对象,它们基本类型的一种映射:String
、Number
、Boolean
。这些内置函数可用于显式地在不一样类型之间进行转换。
44 - "alex"
的输出结果是?
44 + "alex"
的输出结果是?为啥?
"alex" + { name: "Alex" }
的输出结果是 ?
["alex"] == "alex" 输出结果是啥?为何呢?
undefined == null
输出结果是啥?为何呢?
代码部署后可能存在的BUG无法实时知道,过后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给你们推荐一个好用的BUG监控工具 Fundebug。
阿里云最近在作活动,低至2折,有兴趣能够看看:promotion.aliyun.com/ntms/yunpar…
干货系列文章汇总以下,以为不错点个Star,欢迎 加群 互相学习。
由于篇幅的限制,今天的分享只到这里。若是你们想了解更多的内容的话,能够去扫一扫每篇文章最下面的二维码,而后关注我们的微信公众号,了解更多的资讯和有价值的内容。
每次整理文章,通常都到2点才睡觉,一周4次左右,挺苦的,还望支持,给点鼓励