ES 中有5种简单数据类型(也成为基本数据类型):Undefined
Null
Boolean
Number
和 String
,还有一种复杂数据类型:Object
。ES 不支持任何创建自定义类型的机制,而所有值最终都将是上述六种数据类型之一。
ES 6 引入了一种新的基本类型:符号(Symbol
)。
1.typeof 操作符
鉴于 ES 是松散类型的,因此需要有一种手段来检测给定变量的数据类型—— typeof
就是负责提供这方面信息的操作符。对一个值使用 typeof
操作符可能返回下列某个字符串:
"undefined"
:未定义"boolean"
:布尔值"string"
:字符串"number"
:数值"object"
:对象或null
"function"
:函数
typeof
操作符的操作数可以是变量,也可以是数值字面量。注意,typeof
是一个操作符而不是函数,因此后面可以不使用圆括号。
有些时候,typeof
操作符会返回一些令人迷惑但技术上却正确的值。比如,调用 typeof null
会返回 "object"
,因为特殊值 null
被认为是一个空的对象引用。在 Safari5 及之前版本、Chrome7 及之前版本在对正则表达式调用 typeof
操作符时会返回 "function"
,而其他浏览器在这种情况下会返回 "object"
。
2.Undefined 类型
Undefined
类型只有一个值,即特殊的 undefined
。在使用 var
声明变量但未对其加以初始化时,这个变量的值就是 undefined
,例如:
1 | var message; |
这个例子只声明了变量 message
,但未对其进行初始化。比较这个变量与 undefined
字面量,结果表明它们是相等的,因为未经初始化的值默认就会取得 undefined
值。
一般而言,不存在需要显式地把一个变量设置为 undefined
值的情况。字面量 undefined
的主要目的是用于比较。在 ES3 之前的版本中没有规定这个值,第 3 版引入这个值是为了正式区分空对象指针与未经初始化的变量。
不过,包含 undefined
值的变量与尚未定义的变量还是不一样的。例如:
1 | var message; // 这个变量声明之后默认取得了 undefined 值 |
对于尚未声明过的变量,只能执行一项操作,即使用 typeof
操作符检测其数据类型(对未经声明的变量调用 delete
不会导致错误,但这样做没有什么实际意义,而且在严格模式下确实会导致错误)。
然而,令人困惑的是:对未经初始化的变量执行 typeof
操作会返回 undefined
值,而对未声明的变量执行 typeof
操作符同样也会返回 undefined
值。
1 | var message; // 这个变量声明之后默认取得了 undefined 值 |
结果表明,对未初始化和未声明的变量执行 typeof
操作符都返回了 undefined
值;这个结果有其逻辑上的合理性。因为虽然这两种变量从技术角度看有本质区别,但实际上无论对哪种变量也不可能执行真正的操作。
即便未初始化的变量会自动被赋予 undefined
值,但显式地初始化变量依然是明智的选择。如果能够做到这一点,那么当 typeof
操作符返回 "undefined"
时,我们就知道被检测的变量还没有被声明,而不是尚未初始化。
3.Null 类型
Null
类型是第二个只有一个值的数据类型,这个特殊的值是 null
。从逻辑角度来看,null
值表示一个空对象指针,而这也正是使用 typeof
操作符检测 null
值时会返回 "object"
的原因,如下面的例子所示:
1 | var car = null; |
如果定义的变量准备在将来用于保存对象,那么最好将该变量初始化为 null
而不是其他值。这样一来,只要直接检查 null
值就可以知道相应的变量是否已经保存了一个对象的引用,如下面的例子所示:
1 | if (car != null) { |
实际上,undefined
值是派生自 null
值的,因此 ES 规定对它们的相等性测试要返回 true
。
1 | alert(null == undefined); // true |
这里,位于 null
和 undefined
之间的相等操作符(==
)总是返回 true
,不过要注意的是,这个操作符出于比较的目的会转换其操作数。
尽管 null
和 undefined
有这样的关系,但它们的用途完全不同。如前所述,无论在什么情况下都没有必要把一个变量的值显式地设置为 undefined
,可是同样的规则对 null
却不适用。换句话说,只要意在保存对象的变量还没有真正保存对象,就应该明确地让该变量保存 null
值。这样做不仅可以体现 null
作为空对象指针的惯例,而且也有助于进一步区分 null
和 undefined
。
4.Boolean 类型
Boolean 类型是 ES 中使用得最多的一种类型,该类型只有两个字面值:true
和 false
。这两个值与数字值不是一回事,因此 true
不一定等于 1,而 false
也不一定等于 0。以下是为变量赋 Boolean 类型值的例子:
1 | var found = true; |
需要注意的是,Boolean 类型的字面值 true
和 false
是区分大小写的。也就是说,True
和 False
都不是 Boolean 值,只是标识符。
虽然 Boolean 类型的字面值只有两个,但 ES 中所有类型的值都有与这两个 Boolean 值等价的值。要将一个值转换为其对应的 Boolean 值,可以调用转型函数 Boolean(),例如:
1 | var message = "Hello World!"; |
在这个例子中,字符串 message
被转换成了一个 Boolean 值,该值被保存在 messageAsBoolean
变量中。可以对任何数据类型的值调用 Boolean()
函数,而且总会返回一个 Boolean 值。至于返回的这个值是 true
还是 false
,取决于要转换值的数据类型及其实际值。
数据类型 | 转换为 true 的值 | 转换为 false 的值 |
---|---|---|
Boolean | true | false |
String | 任何非空字符串 | “”(空字符串) |
Number | 任何非零数字值(包括无穷大) | 0 和 NaN |
Object | 任何对象 | null |
Undefined | - | undefined |
这些转换规则对理解流控制语句(如 if 语句)自动执行相应的 Boolean 转换非常重要,请看下面的代码:
1 | var message = "Hello world!"; |
运行这个示例,就会显示一个警告框,因为字符串 message
被自动转换成了对应的 Boolean 值(true
)。由于存在这种自动执行的 Boolean 转换,因此确切地知道在流控制语句中使用的是什么变量至关重要。错误地使用一个对象而不是一个 Boolean 值,就有可能彻底改变应用程序的流程。
5.Number 类型
Number 类型应该是 ES 中最令人关注的数据类型了,这种类型使用 IEEE754 格式来表示整数和浮点数值(浮点数值在某些语言中也被称为双精度数值)。为支持各种数值类型,ES 定义了不同的数值字面量格式。
最基本的数值字面量格式是十进制整数,十进制整数可以像下面这样直接在代码中输入:
1 | var intNum = 55; // 整数 |
除了以十进制表示外,整数还可以通过八进制(以 8 为基数)或十六进制(以 16 为基数)的字面值来表示。其中,八进制字面值的第一位必须是零(0),然后是八进制数字序列(0 - 7)。如果字面值中的数值超出了范围,那么前导零将被忽略,后面的数值将被当作十进制数值解析。例如:
1 | var octalNum1 = 070; // 八进制的 56 |
八进制字面量在严格模式下是无效的,会导致支持的 JavaScript 引擎抛出错误。
十六进制字面值的前两位必须是 0x
,后跟任何十六进制数字(0 - 9 及 A - F)。其中,字母 A - F 可以大写,也可以小写。例如:
1 | var hexNum1 = 0xA; // 十六进制的 10 |
在进行算术计算时,所有以八进制和十六进制表示的数值最终都将被转换为十进制数值。
JavaScript 中可以保存正零(+0)和负零(-0)。正零和负零被认为相等。
5.1 浮点数值
所谓浮点数值,就是该数值中必须包含一个小数点,并且小数点后面必须至少有一位数字。
由于保存浮点数值需要的内存空间是保存整数值的两倍,因此 ES 会不失时机地将浮点数值转换为整数值。如果小数点后面没有跟任何数字,那么这个数值就可以作为整数值来保存。同样地,如果浮点数值本身表示的就是一个整数(如 1.0),那么该值也会被转换为整数。
1 | var floatNum1 = 1.; // 解析为1 |
对于极大或极小的数值,可以使用 e表示法(科学计数法)表示的浮点数值表示。用 e表示法表示的数值等于 e
前面的数值乘以 10 的指数次幂。ES 中 e表示法的格式也是如此,即前面是一个数值(可以是整数也可以是浮点数),中间是一个大写或小写的字母 E,后面是 10 的幂中的指数,该幂值将用来与前面的数相乘。
1 | var floatNum = 3.125e7; // 等于 31250000 |
这个例子中,使用 e表示法表示的变量 floatNum
的形式虽然简洁,但它的实际值则是 31250000
。在此,e表示法的实际含义就是 “3.125 乘以 10 的 7 次方”。
也可以使用 e表示法表示极小的数值,如 0.00000000000000003
,这个数值可以使用 3e-17
表示。默认情况下,ES 会将小数点后面带有 6 个以上零的浮点数值转换为 e表示法来表示。
浮点数值的最高精度是 17 位小数,但在进行算术计算时其精确度远远不如整数。例如,0.1
加 0.2
的结果不是 0.3
,而是 0.30000000000000004
。这一误差导致无法测试特定的浮点数值。例如:
1 | if (a + b == 0.3) { // 不要做这样的测试 |
浮点数值计算会产生舍入误差的问题,是来自于 IEEE754 数值的浮点计算的通病,并非 ES 本身的问题。
5.2 数值范围
由于内存的限制,ES 并不能保存世界上所有的数值。ES 能够表示的最小数值保存在 Number.MIN_VALUE
中——在大多数浏览器中,这个值是 5e-324
;能够表示的最大数值保存在 Number.MAX_VALUE
中——在大多数浏览器中,这个值是 1.7976931348623157e+308
。如果某次计算的结果得到了一个超出 JS 数值范围的值,那么这个数值将被自动转换成特殊的 Infinity
值。具体来说,如果这个数值是负数,则会被转换成 -Infinity
(负无穷),如果这个数值是正数,则会被转换成 Infinity
(正无穷)。
如上所述,如果某次计算返回了正或负的 Infinity
值,那么该值将无法继续参与下一次的计算,因为 Infinity
不是能够参与计算的数值。要想确定一个数值是不是有穷的,可以使用 isFinite()
函数。这个函数在参数位于最小与最大数值之间时会返回 true
,例如:
1 | var result = Number.MAX_VALUE + Number.MAX_VALUE; |
尽管在计算中很少出现某些值超出表示范围的情况,但在执行极小或极大数值的计算时,检测监控这些值是可能的,也是必须的。
访问 Number.NEGATIVE_INFINITY
和 Number.POSITIVE_INFINITY
也可以得到负和正的 Infinity
的值。可以想见,这两个属性中分别保存着 -Infinity
和 Infinity
。
5.3 NaN
NaN
,即非数值(Not a Number)是一个特殊的数值,这个数值用于表示一个本来要返回数值的操作数未返回数值的情况(这样就不会抛出错误了)。
0
除以 0
会返回 NaN
,整数除以 0
返回 Infinity
,负数除以 0
返回 -Infinity
。
NaN
本身有两个非同寻常的特点。首先,任何涉及 NaN
的操作(例如 NaN / 10
)都会返回 NaN
,这个特点在多步计算机中可能导致问题。其次,NaN
与任何值都不相等,包括 NaN
本身。例如,下面的代码会返回 false
:
1 | alert(NaN == NaN); // false |
针对 NaN
的这两个特点,ES 定义了 isNaN()
函数。这个函数接受一个参数,该参数可以是任何类型,而函数会帮我们确定这个参数是否“不是数值”。isNaN()
在接收到一个值之后,会尝试将这个值转换为数值。某些不是数值的值会直接转换为数值,例如字符串 "10"
或 Boolean
值。而任何不能被转换为数值的值都会导致整个函数返回 true
。例如:
1 | alert(isNaN(NaN)); // true |
这个例子测试了 5 个不同的值。测试的第一个值是 NaN
本身,结果当然返回 true
。然后测试了数值 10
和字符串 "10"
,结果这两个测试都返回了 false
,因为前者本身就是数值,而后者可以被转换成数值。但是,字符串 "blue"
不能被转换成数值,因此函数返回了 tru
。由于 Boolean
值 true
可以转换成数值 1
,因此函数返回 false
。
isNaN()
也适用于对象。在基于对象调用 isNaN()
函数时,会首先调用对象的 valueOf()
方法,然后确定该方法返回的值是否可以转换为数值。如果不能,则基于这个返回值再调用 toString()
方法,再测试返回值。而这个过程也是 ES 中内置函数和操作符的一般执行流程。
5.4 数值转换
有 3 个函数可以把非数值转换为数值:Number()
、parseInt()
和 parseFloat()
。第一个函数,即转型函数 Number()
可以用于任何数据类型,而另两个函数则专门用于把字符串转换成数值。这 3 个函数对于同样的输入会有返回不同的结果。
Number()
函数的转换规则如下:
- 如果是 Boolean 值,
true
和false
将分别被转换为1
和0
; - 如果是数字值,只是简单的传入和返回;
- 如果是
null
值,返回0
; - 如果是
undefined
, 返回NaN
; - 如果是字符串,遵循下列规则:
– 如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即 "1"
会变成 1
,"011"
会变成 11
(前面的 0
被忽略了);
– 如果字符串中包含有效的浮点格式,如 "1.1"
,则将其转换为对应的浮点数值(同样会忽略前导 0
);
– 如果字符串中包含有效的十六进制格式,例如 "0xf"
,则将其转换为相同大小的十进制整数值;
– 如果字符串是空的(不包含任何字符,或只有空格),则将其转换为 0
;
– 如果字符串中包含除上述格式之外的字符,则将其转换为 NaN
。
- 如果是对象,则调用对象的
valueOf()
方法,然后依照前面的规则转换返回的值。如果转换的结果是NaN
,则调用对象的toString()
方法,然后再次依照前面的规则转换返回的字符串值。
根据这么多的规则使用 Number()
把各种数据类型转换为数值确实有点复杂,下面是几个具体的例子。
1 | var num1 = Number("Hello world!"); // NaN |
一元加操作符的操作与 Number()
函数相同。
由于 Number()
函数在转换字符串时比较复杂而且不够合理,因此在处理整数的时候更常用的是 parseInt()
函数。parseInt()
函数在转换字符串时,更多的是看其是否符合数值模式。它会忽略字符串前面的空格,直到找到第一个非空格字符。如果第一个字符不是数字字符或者正负号,parseInt()
就会返回 NaN
;也就是说,用 parseInt()
转换空字符串会返回 NaN
(Number()
对空字符串返回 0
)。如果第一个字符是数字字符,parseInt()
会继续解析第二个字符,直到解析完所有后续字符或者遇到了一个非数字字符。例如,"1234blue"
会被转换为 1234
,"22.5"
会被转换为 22
(小数点不是有效的数字字符)。
如果字符串中的第一个字符是数字字符,parseInt()
也能够识别出各种整数格式(十进制、八进制和十六进制)。也就是说,如果字符串以 "0x"
开头且后面跟数字字符,就会将其当作一个十六进制整数;如果字符串以 "0"
开头且后面跟数字字符,则会将其当作一个八进制数来解析(ES 3 和 ES 5 在这一点上存在分歧)。
1 | var num1 = parseInt("1234blue"); // 1234 |
在使用 parseInt()
解析像八进制字面量的字符串时,ES 3 与 ES 5 存在分歧,例如:
1 | // ES 3 认为是 56 (八进制),ES 5 认为是 70 (十进制) |
在 ES 3 JavaScript 引擎中,"070"
被当成八进制字面量,因此转换后的值是十进制的 56
。而在 ES 5 JavaScript 引擎中,parseInt()
已经不具有解析八进制值的能力,因此前导的零会被认为无效,从而将这个值当成 "70"
,结果就得到十进制的 70
。在 ES 5 中,即使是非严格模式下也会如此。
为了消除在使用 parseInt()
函数时可能导致的上述困惑,可以为这个函数提供第二个参数:转换时使用的基数(即多少进制)。如果知道要解析的值是十六进制格式的字符串,那么指定基数 16 作为第二个参数,可以保证得到正确的结果,例如:
1 | var num = parseInt("0xAF", 16); // 175 |
实际上,如果指定了 16 作为第二个参数,字符串可以不带前面的 "0x"
,例如:
1 | var num1 = parseInt("AF", 16); // 175 |
上面的例子中第一个转换成功了,而第二个则失败了。差别在于第一个转换传入了基数,明确告诉 parseInt()
要解析一个十六进制格式的字符串;而第二个转换发现第一个字符不是数字字符,因此就自动终止了。
指定基数会影响到转换的输出结果。例如:
1 | var num1 = parseInt("10", 2); // 2 (按二进制解析) |
不指定基数意味着让 parseInt()
决定如何解析输入的字符串,因此为了避免错误的解析,建议无论在什么情况下都明确指定基数。
多数情况下,我们要解析的都是十进制数值,因此始终将 10
作为第二个参数是非常必要的。
注意:parseInt()
的第二个参数可以是从 2
到 36
的数值,如果超出了这个范围,则 parseInt()
会返回 NaN
。
与 parseInt()
函数类似,parseFloat()
也是从第一个字符(位置 0)开始解析每个字符。而且也是一直解析到字符串末尾,或者解析到遇见一个无效的浮点数数字字符为止。也就是说,字符串中的第一个小数点是有效的,而第二个小数点就是无效的了,因此它后面的字符串将被忽略。举例来说,"22.34.5"
会被转换为 22.34
。
除了第一个小数点有效之外,parseFloat()
与 parseInt()
的第二个区别在于它始终都会忽略前导的零。parseFloat()
可以识别前面讨论过的所有浮点数值格式,也包括十进制整数格式。但十六进制格式的字符串则始终会被转换成 0
。由于 parseFloat()
只解析十进制值,因此它没有用第二个参数指定基数的用法。最后还要注意一点:如果字符串包含的是一个可解析为整数的数(没有小数点,或者小数点后都是零),parseFloat()
会返回整数。
1 | var num1 = parseFloat("1234blue"); // 1234 (整数) |
6.String 类型
String 类型由于表示由零或多个 16 位的 Unicode 字符组成的字符序列,即字符串。字符串可以由双引号("
)或单引号('
)表示。
与 PHP 中双引号和单引号会影响字符串的解释方式不同,ES 中的这两种写法没有什么区别。用双引号表示的字符串和用单引号表示的字符串完全相同。不过,以双引号开头的字符串也必须以双引号结尾,而以单引号开头的字符串必须以单引号结尾。例如,下面这种字符串表示法会导致语法错误:
1 | var firstName = 'Nicholas"; // 语法错误(左右引号必须匹配) |
6.1 字符字面量
String 数据类型包含一些特殊的字符字面量,也叫转义序列,用于表示非打印字符,或者具有其他用途的字符。这些字面量如下表所示:
字面量 | 含义 |
---|---|
\n | 换行 |
\t | 制表 |
\b | 空格 |
\r | 回车 |
\f | 进纸 |
\\ | 斜杠 |
\‘ | 单引号,在用单引号表示的字符串中使用,例如:’He said, \‘hey.\‘’ |
\“ | 双引号,在用双引号表示的字符串中使用,例如:”He said, \“hey.\“” |
\xnn | 以十六进制代码 nn 表示的一个字符(其中 n 为 0~F)。例如,\x41 表示 “A” |
\unnnn | 以十六进制代码 nnnn 表示的一个 Unicode 字符(其中 n 为 0~F)。例如,\u03a3 表示希腊字符 Σ |
这些字符字面量可以出现在字符串中的任意位置,而且也将被作为一个字符来解析,例如:
1 | var text = "This is the letter sigma: \u03a3."; |
这个例子中的变量 text
有 28 个字符,其中 6 个字符长的转移序列表示 1 个字符。
任何字符串的长度都可以通过访问其 length
属性取得,例如:
1 | alert(text.length); // 输出 28 |
这个属性返回的字符数包括 16 位字符的数目。如果字符串中包含双字节字符,那么 length
属性可能不会精确地返回字符串中的字符数目。
6.2 字符串的特点
ES 中的字符串是不可变的,也就是说,字符串一旦创建,它们的值就不能改变。要改变某个变量保存的字符串,首先要销毁原来的字符串,然后再用另一个包含新值的字符串填充该变量。
1 | var lang = "Java"; |
以上示例中的变量 lang
开始时包含字符串 "Java"
。而第二行代码把 lang
的值重新定义为 "JavaScript"
。实现这个操作的过程如下:首先创建一个能容纳 10 个字符的新字符串,然后在这个字符串中填充 "Java"
和 "Script"
,最后一步是销毁原来的字符串 "Java"
和字符串 "Script"
,因为这两个字符已经没用了。这个过程是在后台发生的,而这也是在某些旧版本的浏览器(如版本低于 1.0 的 Firefox、IE6 等)中拼接字符串速度很慢的原因所在。但这些浏览器后来的版本已经解决了这个低效率问题。
6.3 转换为字符串
要把一个值转换为一个字符串有两种方式。第一种是使用几乎每个值都有的 toString()
方法。这个方法唯一要做的就是返回相应值的字符串表现。
1 | var age = 11; |
数值、布尔值、对象和字符串值(字符串的 toString()
方法返回该字符串的一个副本)都有 toString()
方法。但 null
和 undefined
值都没有这个方法。
多数情况下,调用 toString()
方法不必传递参数。但是,在调用数值的 toString()
方法时,可以传递一个参数:输出值的基数。默认情况下,toString()
方法以十进制格式返回数值的字符串表示。而通过传递基数,toString()
可以输出以二进制、八进制、十六进制,乃至其他任意有效进制格式表示的字符串值。例如:
1 | var num = 10; |
toString()
同样只能接收 2~36 之间的数值,否则会抛出错误(RangeError)。
注意,直接对数值调用 toString()
方法会抛出错误(TypeError)
通过这个例子可以看出,通过指定基数,toString()
方法会改变输出的值。而数值 10
根据基数的不同,可以在输出时被转换为不同的数值格式。注意,默认的(没有参数的)输出值与指定基数 10
时的输出值相同。
在不知道要转换的值是不是 null
或 undefined
的情况下,还可以使用转型函数 String()
,这个函数能够将任何类型的值转换为字符串。String()
函数遵循下列转换规则:
- 如果值由
toString()
方法, 则调用该方法(没有参数)并返回相应的结果; - 如果值是
null
,则返回"null"
; - 如果值是
undefined
,则返回"undefined"
;
null
和 undefined
没有 toString()
方法,因此不能对 null
和 undefined
调用 toString()
;而 String()
函数属于全局对象 Global
,可以将 null
或 undefined
作为参数传递给 String()
函数。
1 | var value1 = 10; |
这里先后转换了 4 个值:数值、布尔值、null 和 undefined。数值和布尔值的转换结果与调用 toString()
方法得到的结果相同。因为 null
和 undefined
没有 toString()
方法,所以 String()
函数就返回了这两个值的字面量。
要把某个值转换为字符串,可以使用加号操作符把它与一个字符串(""
)加在一起。
7.Object 类型
ES 中的对象其实就是一组数据和功能的集合。对象可以通过执行 new
操作符后跟要创建的对象类型的名称来创建。而创建 Object 类型的实例并为其添加属性和(或)方法,就可以创建自定义对象,例如:
1 | var o = new Object(); |
这个语法与 Java 中创建对象的语法相似;但在 ES 中,如果不给构造函数传递参数,则可以省略后面的那一对圆括号(不推荐)。
1 | var o = new Object; // 有效,但不推荐省略圆括号 |
仅仅创建 Object 的实例并没有什么用处,关键是要理解一个重要是思想:在 ES 中,Object 类型是所有它的实例的基础。也就是说,Object 类型所具有的任何属性和方法也同样存在于更具体的对象中。
Object 的每个实例都具有下列属性和方法:
- constructor: 保存着用于创建当前对象的函数。对于前面的例子而言,构造函数(constructor)就是
Object()
。 - hasOwnProperty(propertyName):用于检查给定的属性在当前的对象实例中(而不是在实例的原型中)是否存在。其中,作为参数的属性名(propertyName)必须以字符串形式指定(例如:
o.hasOwnProperty("name")
)。 - isPrototypeOf(object):用于检查传入的对象是否是传入对象的原型。
- propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用
for-in
语句来枚举。与hasOwnProperty()
方法一样,作为参数的属性名必须以字符串形式指定。 - toLocaleString():返回对象的字符串表示,该字符串与执行环境的地区对应。
- toString():返回对象的字符串表示。
- valueOf():返回对象的字符串、数值或布尔值表示,通常与
toString()
方法的返回值相同。
由于在 ES 中 Object 是所有对象的基础,因此所有对象都具有这些基本的属性和方法。
1.从技术角度将,ES 中对象的行为不一定适用于 JavaScript 中的其他对象。浏览器环境中的对象,比如 BOM 和 DOM 中的对象,都属于宿主对象,因为它们是由宿主实现提供和定义的。ES 不负责定义宿主对象,因此宿主对象可能会也可能不会继承 Object。
2.通过 Object.create(null)
方式创建的对象,没有以上这些属性和方法。
toString() 与 toLocaleString() 的区别:
第一个区别发生在对数值的转换上:
1 | var a = 123; |
可以看到,toString()
会将数值按原样转换为字符串;而 toLocaleString()
会将数值的整数部分按照千分位进行分隔,将数值的小数部分按四舍五入保留 3 位小数,然后再转换位字符串;
第二个区别体现在对 Date 对象的操作上:
1 | var d = new Date(); // Tue Jan 14 2020 20:35:32 GMT+0800 (中国标准时间) |