www.zhblog.net

增强的数值与字符串


JavaScript 中的基本数据类型包括了数值、字符串与布尔值,类型名称分别为numberstring与布尔值boolean,在 ES6 中,多了个symbol,这会在下一篇文件中说明。

至于number的部份,在 ES6 中,可以使用Number.MAX_SAFE_INTEGERNumber.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
>

只不过,这就与NumbertoString字符串不一致了,因为它少了 0b 或 0o 的前置:

> (4).toString(2)
'100'
> (63).toString(8)
'77'
> parseInt('100', 2)
4
> parseInt('77', 8)
63
>

NumbertoString(),还是得配合parseInt,不过,ES6 的Number上有个parseInt也有个parseFloat(),与全局的parseIntparseFloat是相同的:

> Number.parseInt === parseInt
true
> Number.parseFloat === parseFloat
true
>

因为 ES6 想要远离全局的束缚,一些原本是全局函数的东西,都被放到了某个名称之下,不过,有些获得了增强,例如Number.isNaNisNaN行为上是不同的,只有NaN能让Number.isNaNtrue了:

> Number.isNaN(NaN);
true
> Number.isNaN(1 / 'two');
true
> Number.isNaN('caterpillar');
false
> Number.isNaN(undefined);
false
> Number.isNaN('0');
false
>

Number.isFiniteisFinite也不同,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
>




展开阅读全文

评论

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 心情