JavaScript 中的基本数据类型包括了数值、字符串与布尔值,类型名称分别为number
、string
与布尔值boolean
,在 ES6 中,多了个symbol
,这会在下一篇文件中说明。
至于number
的部份,在 ES6 中,可以使用Number.MAX_SAFE_INTEGER
与Number.MIN_SAFE_INTEGER
来获取可表达的最大整数与最小整数,而Number.isSafeInteger
可用来检查一个整数是否在安全范围内:
> Number.MAX_SAFE_INTEGER;
9007199254740991
> Number.MIN_SAFE_INTEGER;
-9007199254740991
> Number.isSafeInteger(9007199254740992);
false
> Number.isSafeInteger(9007199254740991);
true
> Number.isInteger(9007199254740992)
true
>
Number.isInteger
只检查数字是不是整数,不会考虑它是不是安全范围内的整数。至于两个符点数之间,最小的差距,可以使用Number.EPSILON
来获取:
> Number.EPSILON;
2.220446049250313e-16
>
可以使用0b
(或0B
) 编写二进制数来表示数字,或者是0o
(或0O
?别这么写啦!)编写八进制数来表示数字。例如:
> 0b0100
4
> 0o77
63
>
(在 ES5 严格模式下,不允许使用八进制077
来表示 63,因为有人会误用 0 来对齐数字。)
如果你有个字符串'0b0100'
、'0o77'
,可以使用Number
(而不是使用parseInt
)来转换为 10 进制数字,例如:
> Number('0b0100')
4
> Number('0o77')
63
>
只不过,这就与Number
的toString
字符串不一致了,因为它少了 0b 或 0o 的前置:
> (4).toString(2)
'100'
> (63).toString(8)
'77'
> parseInt('100', 2)
4
> parseInt('77', 8)
63
>
Number
的toString()
,还是得配合parseInt
,不过,ES6 的Number
上有个parseInt
也有个parseFloat()
,与全局的parseInt
与parseFloat
是相同的:
> Number.parseInt === parseInt
true
> Number.parseFloat === parseFloat
true
>
因为 ES6 想要远离全局的束缚,一些原本是全局函数的东西,都被放到了某个名称之下,不过,有些获得了增强,例如Number.isNaN
与isNaN
行为上是不同的,只有NaN
能让Number.isNaN
为true
了:
> Number.isNaN(NaN);
true
> Number.isNaN(1 / 'two');
true
> Number.isNaN('caterpillar');
false
> Number.isNaN(undefined);
false
> Number.isNaN('0');
false
>
Number.isFinite
与isFinite
也不同,Number.isFinite
遇到非number
就会是false
:
> isFinite('15')
true
> Number.isFinite('15')
false
> Number.isFinite(15);
true
> Number.isFinite(Infinity);
false
>
在字符串的部份,ES6 中,如果字符串中的字符不有 0000 ~ FFFF 的范围之中(也就是 BMP 外的字符),例如高音谱记号的 1D11E,可以直接使用\u{1D11E}
来表示了,使用'\uD834\uDD1E'
也是可以啦!
> '\u{1D11E}' === '\uD834\uDD1E';
true
>
在 ES6 中支持模版字符串(Template string),必须使用 ` 来创建模版字符串,不少文件最爱举的例子是它可以换行,例如,有个 helloworld.js 文件写了以下的内容的话:
let html = `<!DOCTYPE html>
<html>
<head>
<title>Hello, World</title>
</head>
<body>
Hello, World
</body>
</html>`;
console.log(html);
执行这个 .js 文件你会看到:
C:\workspace>node --use_strict helloworld.js
<!DOCTYPE html>
<html>
<head>
<title>Hello, World</title>
</head>
<body>
Hello, World
</body>
</html>
该换行的都换行了,简单来说,它会保留 ` 之间的内容。例如:
> let s = `Your left brain has nothing right.
... Your right brain has nothing left.`
undefined
> s;
'Your left brain has nothing right.\nYour right brain has nothing left.'
> typeof s;
'string'
>
一个模版字符串的类型也是string
。模版字符串中若${}
的部份,会执行${}
中的内容,然后获取结果再与其他字符串结合在一起,例如:
> `1 + 2 = ${1 + 2}`
'1 + 2 = 3'
> let a = 1;
undefined
> let b = 2;
undefined
> `${a} + ${b} == ${a + b}`
'1 + 2 == 3'
> let o = {p : 10};
undefined
> `${o.p}`;
'10'
> let arr = [1, 2, 3];
undefined
> `Double arr: ${arr.map(n => n * 2)}`;
'Double arr: 2,4,6'
>
最后一个看到的是 ES6 的箭头函数(Arrow function),之后就会谈到。可以想见的,如果想要创建模版,例如 HTML,使用模版字符串很方便,例如:
> let title = 'Hello, World';
undefined
> let message = 'Hello? World?';
undefined
> let html = `<!DOCTYPE html>
... <html>
... <head>
... <title>${title}</title>
... </head>
... <body>
... ${message}
... </body>
... </html>`;
undefined
> console.log(html);
<!DOCTYPE html>
<html>
<head>
<title>Hello, World</title>
</head>
<body>
Hello? World?
</body>
</html>
undefined
>
经常被拿来在说明模版字符串之后提及的是标记模版(Tagged template),如前面提过的,模版字符串中若${}
的部份,会执行${}
中的内容,然后获取结果再与其他字符串结合在一起,如果你想分别处理其他字符串以及${}
运算结果,例如${}
可能来自使用者输入,而你想要将有安全疑虑的字符替换掉,那标记模版(Tagged template)就会派上用场。
不过,标记模版其实是个函数调用的特殊形式,如果你有个函数f
,那么:
let a = 10;
let b = 20;
f(`${a} + ${b} = ${a + b}`);
结果就相当于:
f('10 + 20 = 30');
然而,如果你使用:
f`${a} + ${b} = ${a + b}`
就会将${}
外的字符串分割出来,使用数组存储,然后运算出${a}
、${b}
、${a + b}
的值,最后再用数组与运算出来的值来调用函数,也就是相当于:
f(['', ' + ', ' = ', ''], 10, 20, 30);
接下来,就看你的函数中怎么处理这些值了,例如:
function f(strings, value1, value2, value3) {
// 函数处理
}
如果你的标记模版中${}
数量是固定的,这样就够了,不过,若是事先无法决定个数,那么可以定义以下这样的函数:
function f(strings, ...values) {
// 函数处理
}
...
是 ES6 中的 Rest 运算符,当它出现在参数时,会将调用函数时其余的实参收集在一个数组中,当成函数的实参传入,因此就标记模版来说,就是将${}
的结果收集至数组,然后当成第二个实参传入函数了。
如果你想要console.log
能显示'\n'
字样,基本上在字符串中要 escape:
> console.log('ABC\nEFG');
ABC
EFG
undefined
> console.log('ABC\\nEFG');
ABC\nEFG
undefined
> console.log(`ABC\nEFG`);
ABC
EFG
undefined
> console.log(`ABC\\nEFG`);
ABC\nEFG
undefined
>
在 ES6 中,有个String.raw
函数,搭配标记模版,可以直接 escape,让\n
这类的字符,不会被转译为换行:
> String.raw`ABC\nEFG`
'ABC\\nEFG'
> console.log(String.raw`ABC\nEFG`)
ABC\nEFG
undefined
>
函数搭配标记模版时,函数的第一个参数值虽是数组,然而会加上一个raw
特性,可用来获取未转译字符串的清单:
> function f(strings) {
... console.log(strings);
... console.log(strings.raw);
... }
undefined
> f`ABC\nEFG`
[ 'ABC\nEFG' ]
[ 'ABC\\nEFG' ]
undefined
>