《JavaScript面向对象编程指南》——2.3 基本数据类型

简介:

本节书摘来自异步社区《JavaScript面向对象编程指南》一书中的第2章,第2.3节,作者: 【加】Stoyan Stefanov 译者: 凌杰 更多章节内容可以访问云栖社区“异步社区”公众号查看。

2.3 基本数据类型

我们在程序中所使用的任何值都是有类型的。在JavaScript中,主要包含以下几大基本数据类型。

1.数字——包括浮点数与整数,例如1、100、3.14。

2.字符串——一序列由任意数量字符组成的序列,例如"a"、"one"、"one 2 three"。

3.布尔值——true或false。

4.undefined——当我们试图访问一个不存在的变量时,就会得到一个特殊值: undefined。除此之外,使用一个未初始化的变量也会如此。因为JavaScript会自动将变量在初始化之前的值设定为undefined。

5.null——这是另一种只包含一个值的特殊数据类型。所谓的null值,通常是指没有值、空值,不代表任何东西。null与undefined最大的不同在于,被赋予null的变量通常被认为是已经定义了的,只不过它不代表任何东西。关于这一点,我们稍后会通过一些具体的示例来解释。

任何不属于上述五种基本类型的值都会被认为是一个对象。甚至有时候我们也会将null视为对象,这会使人有些尴尬——这是一个不代表任何东西的对象(东西)。我们将会在第4章中深入阐述对象的概念,现在我们只需要记住一点,JavaScript中的数据类型主要分为以下两个部分。

基本类型(上面列出的五种类型)。
非基本类型(即对象)。
2.3.1 查看类型操作符——typeof
如果我们想知道某个变量或值的数据类型,可以调用一种叫做typeof的特殊操作符。该操作符会返回一个代表数据类型的字符串,它的值包括:“number”、“string”、“boolean”、“undefined”、“object”和“function”。在接下来的几节中,我们将会逐一展示对五种基本数据类型使用typeof操作符时的情况。

2.3.2 数字
最简单的数字类型当然就是整数了。如果我们将一个变量赋值为1,并对其调用typeof操作符,控制台就会返回字符串“number”,请看下面的代码。此外要注意的是,当您第二次设置变量值时,就不需要再使用var语句了。

>>> var n = 1;
>>> typeof n;
"number"
>>> n = 1234;
>>> typeof n;
"number"

当然,这也同样适用于浮点数(即含小数部分的数字):

>>> var n2 = 1.23;
>>> typeof n;
"number"

1 除了对变量赋值以外,我们也可以直接对一个数值调用typeof。例如:

>>> typeof 123;
"number"

2.3.2.1 八进制与十六进制
当一个数字以0开头时,就表示这是一个八进制数。例如,八进制数0377所代表的就是十进制数255。

>>> var n3 = 0377;
>>> typeof n3;
"number"
>>> n3;
255

如您所见,例子中最后一行所输出的就是该八进制数的十进制表示形式。如果您对八进制数还不太熟悉,那么十六进制您一定不会感到陌生,毕竟,CSS样式表中的颜色值使用的都是十六进制。

在CSS中,我们定义颜色的方式有以下两种。

使用十进制数分别指定R(红)、G(绿)、B(蓝)的值2,取值范围都为0~255。例如rgb(0,0,0)代表黑色、rgb(255,0,0)代表红色(红值达到最大值,而绿和蓝都为0值)。
使用十六进制数,两个数位代表一种色值,依次是R、G、B。例如#000000代表黑色、#ff0000代表红色,因为十六进制的ff就等于255。
在JavaScript中,我们会用0x前缀来表示一个十六进制值(简称为hex)。

>>> var n4 = 0x00;
>>> typeof n4;
"number"
>>> n4;
0
>>> var n5 = 0xff;
>>> typeof n5;
"number"
>>> n5;
255

2.3.2.2 指数表示法
一个数字可以表示成1e1(或者1e+1、1E1、1E+1)这样的指数形式,意思是在数字1后面加1个0,也就是10。同理,2e+3的意思是在数字2后面加3个0,也就是2000。

>>> 1e1
10
>>> 1e+1
10
>>> 2e+3
2000
>>> typeof 2e+3;
"number"

此外,我们也可以将2e+3理解为将数字2的小数点向右移三位。依照同理,2e-3也就能被理解为是将数字2的小数点左移三位。
screenshot

>>> 2e-3
0.002
>>> 123.456E-3
0.123456
>>> typeof 2e-3
"number"

2.3.2.3 Infinity
在JavaScript中,还有一种叫做Infinity的特殊值。它所代表的是超出了JavaScript处理范围的数值。但Infinity依然是一个数字,我们可以在控制台使用typeof来测试Infinity。当我们输入1e308时,一切正常,但一旦将后面的308改成309就出界了。经实践证明,JavaScript所能处理的最大值是1.7976931348623157e+308,而最小值为5e-324。

>>> Infinity
Infinity
>>> typeof Infinity
"number"
>>> 1e309
Infinity
>>> 1e308
1e+308

另外,任何数除0也为infinity:

>>> var a = 6 / 0;
>>> a
Infinity

Infinity表示的是最大数(或者比最大数还要大的数),那么最小数该如何表示呢?答案是在Infinity之前加一个负号:

>>> var i = -Infinity;
>>> i
-Infinity
>>> typeof i
"number"

但这是不是意味着我们可以得到双倍的Infinity呢?——毕竟我们可以从0加到Infinity,也可以从0减到-Infinity。好吧,这只是个玩笑。事实上这是不可能的,因为即便将正负Infinity相加,我们也不会得到0,而是会得到一个叫做NaN(Not A Number的缩写,即不是数字)的东西。

>>> Infinity - Infinity
NaN
>>> -Infinity + Infinity
NaN

而且,Infinity与其他的任何操作数执行任何算术运算的结果,都是Infinity。

>>> Infinity - 20
Infinity
>>> -Infinity * 3
-Infinity
>>> Infinity / 2
Infinity
>>> Infinity - 99999999999999999
Infinity

2.3.2.4 NaN
还记得之前见过的那个NaN吗?尽管该值的名字叫做“不是数字”,但事实上它依然属于数字,只不过是一种特殊的数字罢了。

>>> typeof NaN
"number"
>>> var a = NaN;
>>> a
NaN

如果我们在对一个假定的数字执行某个操作时失败了,就会得到一个NaN。例如,当我们试图将10与字符"f"相乘时,其结果就会为NaN,因为"f"显然是不支持乘法运算的。

>>> var a = 10 * "f";
>>> a
NaN

而且,NaN是具有传染性的,只要我们的算术运算中存在一个NaN,整个运算就会失败。

>>> 1 + 2 + NaN
NaN

2.3.3 字符串
字符串通常指的是一组用于表示文本的字符序列。在JavaScript中,一对双引号或单引号之间的任何值都会被视为一个字符串。也就是说,1是一个数字的话,"1"就是一个字符串了。在一个字符串上,typeof操作符会返回“string”。

>>> var s = "some characters";
>>> typeof s;
"string"
>>> var s = 'some characters and numbers 123 5.87';
>>> typeof s;
"string"

字符串中可以包含数字,例如:

>>> var s = '1';
>>> typeof s;
"string"

如果引号之间没有任何东西,它所表示的依然是一个字符串(即空字符串):

>>> var s = ""; typeof s;
"string"

之前,当我们在两个数字之间使用加号时,所执行的是加法运算。但在字符串中,这是一个字符串拼接操作,它返回的是两个字符串拼接之后的结果。例如:

>>> var s1 = "one"; var s2 = "two"; var s = s1 + s2; s;
"onetwo"
>>> typeof s;
"string"

像+这样的双功能操作符可能会带来一些错误。因此,我们如果想执行拼接操作的话,最好确保其所有的操作数都是字符串。同样的,在执行数字相加时,我们也要确保其所有的操作数都是数字。至于如何做到这一点,我们将会在后续章节中详细讨论。

2.3.3.1 字符串转换
当我们将一个数字字符串用于算术运算中的操作数时,该字符串会在运算中被当做数字类型来使用。(由于加法操作符的歧义性,这条规则不适用于加法运算。)

>>> var s = '1'; s = 3 * s; typeof s;
"number"
>>> s
3
>>> var s = '1'; s++; typeof s;
"number"
>>> s
2

于是,将数字字符串转换为数字就有了一种偷懒的方法:只需将该字符串与1相乘即可。(当然,更好的选择是调用parseInt函数,关于这点,我们将会在下一章中介绍。)

>>> var s = "100"; typeof s;
"string"
>>> s = s * 1;
100
>>> typeof s;
"number"

如果转换操作失败了,我们就会得到一个NaN值。

>>> var d = '101 dalmatians';
>>> d * 1
NaN

此外,将其他类型转换为字符串也有一种偷懒的方法,只需要将其与空字符串连接即可:

>>> var n = 1;
>>> typeof n;
"number"
>>> n = "" + n;
"1"
>>> typeof n;
"string"

2.3.3.2 特殊字符串
在表2-2中,我们列出了一些具有特殊含义的字符串。
screenshot
screenshot

除此之外,还有一些很少被使用的特殊字符,例如:b(退格符)、v(纵向制表符)、f(换页符)等。

2.3.4 布尔值
布尔类型中只有两种值:true和false。它们可用于引号以外的任何地方。

>>> var b = true; typeof b;
"boolean"
>>> var b = false; typeof b;
"boolean"

如果true或false在引号内,它就是一个字符串。

>>> var b = "true"; typeof b;
"string"

2.3.4.1 逻辑运算符
在JavaScript中,主要有三种逻辑运算符,它们都属于布尔运算。分别是:

!——逻辑非(取反)。
&&——逻辑与。
||——逻辑或。
在JavaScript中,如果我们想描述一些日常生活中非真即假的事物,就可以考虑使用逻辑非运算符:

>>> var b = !true;
>>> b;
false

如果在同一个值上执行两次逻辑非运算,其结果就等于原值3:

>>> var b = !!true;
>>> b;
true

如果在一个非布尔值上执行逻辑运算,该值会在计算期间被转换为布尔值:

>>> var b = "one";
>>> !b;
false

如您所见,上例中的字符串"one"是先被转换为布尔值true然后再取反的,结果为false。如果我们对它取反两次,结果就会为true。例如:

>>> var b = "one";
>>> !!b;
true

使用双重取反操作可以很容易地将任何值转换为等效的布尔值。虽然这种方法很少被用到,但从另一个角度也说明了将其他类型的值转换为布尔值的重要性。而事实上,除了下面所列出特定值以外(它们将被转换为false),其余大部分值在转换为布尔值时都为true。

空字符串""
null
undefined
数字0
数字NaN
布尔值false
这6个值有时也会被我们统称为falsy,而其他值则被称为truthy(包括字符串"0"、""、"false")。

接下来,让我们来看看另外两个操作符——逻辑与和逻辑或的使用示例。当我们使用逻辑与操作符时,当且仅当该操作所有操作数为true时,它才为true。而逻辑或操作则只需要至少一个操作数为true即可为true。

>>> var b1 = true; var b2 = false;
>>> b1 || b2
true
>>> b1 && b2
false

在表2-3中,我们列出了所有可能的情况及其相应结果。
screenshot

当然,我们也能连续执行若干个逻辑操作。例如:

>>> true && true && false && true
false
>>> false || true || false
true

我们还可以在同一个表达式中混合使用&&和||。不过在这种情况下,我们最好用括号来明确一下操作顺序。例如:

>>> false && false || true && true
true
>>> false && (false || true) && true
false

2.3.4.2 操作符优先级
您可能会想知道,为什么上例中的第一个表达式(false && false || true && true)结果为true。答案在于操作符优先级。这看上去有点像数学,例如:

>>> 1 + 2 * 3
7

由于乘法运算的优先级高于加法,所以该表达式会先计算2* 3,这就相当于我们输入的表达式是:

> >>> 1 + (2 * 3)
7

逻辑运算符也一样,!的优先级最高,因此在没有括号限定的情况下它将会被最先执行。然后,接下来的优先顺序是先&&后||。也就是说:

>>> false && false || true && true
true

与下面表达式等效:

>>> (false && false) || (true && true)
true

最佳方法:

尽量使用括号,而不是依靠操作符优先级来设定代码的执行顺序,这样我们的代码才能有更好的可读性。
2.3.4.3 惰性求值
如果在一个连续的逻辑操作中,操作结果在最后一个操作完成之前就已经明确了的话,那么该操作往往就不必再继续执行了,因为这已经不会对最终结果产生任何影响。例如,在下面这种情况中:

>>> true || false || true || false || true
true

在这里,所有的逻辑或运算符优先级都是相同的,只要其中任何一个操作数为true,该表达式的结果就为true。因而当第一个操作数被求值之后,无论后面的值是什么,结果都已经被确定了。于是我们可以允许JavaScript引擎偷个懒(好吧,这也是为了提高效率),在不影响最终结果的情况下省略一些不必要的求值操作。为此,我们可以在控制台中做个实验:

>>> var b = 5;
>>> true || (b = 6)
true
>>> b
5
>>> true && (b = 6)
6
>>> b
6

除此之外,上面的例子还向我们显示了另一个有趣的事情——如果JavaScript引擎在一个逻辑表达式中遇到一个非布尔类型的操作数,那么该操作数的值就会成为该表达式所返回的结果。例如:

>>> true || "something"
true
>>> true && "something"
"something"

通常情况下,这种行为是应该尽量避免的,因为它会使我们的代码变得难以理解。但在某些时候这样做也是有用的。例如,当我们不能确定某个变量是否已经被定义时,就可以像下面这样,即如果变量mynumber已经被定义了,就保留其原有值,否则就将它初始化为10。

var mynumber = mynumber || 10;

这种做法简单而优雅,但是请注意,这也不是绝对安全的。如果这里的mynumber之前被初始化为0(或者是那6个falsy值中的任何一个),这段代码就不太可能如我们所愿了。

2.3.4.4 比较运算符
在JavaScript中,还有另外一组以布尔值为返回值类型的操作符,即比较操作符。下面让我们通过表2-4来了解一下它们以及相关的示例。

screenshot
screenshot

screenshot

还有一件有趣的事情要提醒读者注意:NaN不等于任何东西,包括它自己。

>>> NaN == NaN
false

2.3.5 undefined与null
通常情况下,当我们试图访问某个不存在的或者未经赋值的变量时,就会得到一个undefined值。JavaScript会自动将声明时没有进行初始化的变量设为undefined。

当我们试图使用一个不存在的变量时,就会得到这样的错误信息:

>>> foo
foo is not defined

这时候,如果我们在该变量上调用typeof操作符,就会得到字符串“undefined”:

>>> typeof foo
"undefined"

如果我们声明一个变量时没有对其进行赋值,调用该变量时并不会出错,但typeof操作符依然会返回“undefined”。

>>> var somevar;
>>> somevar
>>> typeof somevar
"undefined"

而null值就完全是另一回事了。它不能通过JavaScript来自动赋值,只能通过我们的代码来完成。

>>> var somevar = null
null
>>> somevar
null
>>> typeof somevar
"object"

尽管undefined和null之间的差别微乎其微,但有时候也很重要。例如,当我们对其分别执行某种算术运算时,结果就会截然不同:

>>> var i = 1 + undefined; i;
NaN
>>> var i = 1 + null; i;
1

这是因为null和undefined在被转换为其他基本类型时,方法存在一定的区别,下面我们给出一些可能的转换类型。

转换成数字:

>>> 1*undefined
NaN
>>> 1*null
0

转换成布尔值:

>>> !!undefined
false
>>> !!null
false

转换成字符串:

>>> "" + null
"null"
>>> "" + undefined
"undefined"
相关文章
|
8天前
|
JavaScript
JS 获取对象数据类型的键值对的键与值
JS 获取对象数据类型的键值对的键与值
|
JavaScript 前端开发 Java
深入JS面向对象(原型-继承)(一)
深入JS面向对象(原型-继承)
30 0
|
1月前
|
JavaScript 前端开发
JavaScript 中有哪些数据类型?
JavaScript 中有哪些数据类型?
18 3
|
1月前
|
JavaScript
JS常用数据类型转换
JS常用数据类型转换
13 1
|
1月前
|
存储 JavaScript 前端开发
javascript的8中数据类型
javascript的8中数据类型
|
1月前
|
JavaScript 前端开发 开发者
编程笔记 html5&css&js 071 JavaScript Symbol 数据类型
编程笔记 html5&css&js 071 JavaScript Symbol 数据类型
|
1天前
|
JavaScript 前端开发
js数据类型有几类?一共有几种?判断数据类型的方法是什么?
js数据类型有几类?一共有几种?判断数据类型的方法是什么?
|
3天前
|
存储 JavaScript 前端开发
JavaScript的引用数据类型主要包括对象
【4月更文挑战第16天】JavaScript的引用数据类型主要包括对象
16 4
|
1月前
|
JavaScript
|
1月前
|
JSON JavaScript 前端开发
js如何正确判断数据类型
js如何正确判断数据类型
24 0