JavaScript 类型转换:数字转换和 Symbol 类型转换

数字转换

将数据类型转换为数字称为数字转换,可以使用Number()parseInt()parseFloat()等方法将数据类型显式转换为数字。当一个值不能被强制转换为一个数字时,就会返回 NaN

1. 字符串 => 数字:

当把字符串转换为数字时,JavaScript 引擎首先会修剪前导和后置空格、\n\t 字符,如果修剪后的字符串不代表有效数字,则返回 NaN。 如果字符串为空,则返回 0。

Number('123');            // 123
Number("-12.34")          // -12.34
Number("12s");            // NaN
Number("\n")              // 0

parseInt(' 203px');       // 203 
parseInt('10.000')        // 10   
parseInt('10.20')         // 10 
parseFloat('203.212px');  // 203.212
parseFloat('10.20')       // 10.2
parseFloat('10.81')       // 10.81

fileOf7174.png

可以看到,parseInt 函数会从字符串中读取一个数字并删除它后面所有字符,但是如果数字前面有字符(空格除外),那么它将输出 NaN

2. 布尔值 => 数字:

当使用 Number() 将布尔值转化为数字时,true 会转化为 1,false 会转化为 0。

Number(true);  // 1
Number(false); // 0

3. null  => 数字:

当使用 Number() 将 null 转化为数字时,会返回 0:

Number(null); // 0
null + 5; // 5

4. undefined / 数组 / 对象 / NaN => 数字:

当使用 Number() 将 undefined、数组、对象、NaN 转化为数字时,会返回 NaN

Number(undefined);  // NaN
Number([1, 2, 3])   // NaN
Number({})          // NaN
Number(NaN)         // NaN

5. 数组元素

可以使用map遍历数组元素,并使用需要的类型来进行类型转换:

["1", "9", "-9", "0.003", "yes"].map(Number);
// 输出结果:[1, 9, -9, 0.003, NaN]

6. 特殊规则

在表达式中,当我们将 == 运算符应用于 null 或 undefined 时,不会发生数字转换。 此外,null 只等于 null 或 undefined,不能等于其他任何值:

null == null;           // true 
null == 0;              // false
null == undefined;      // true
undefined == undefined  // true

fileOf7174.png

根据运算符优先级,+ 运算符具有从左到右的关联性,因此如果有一个表达式 2 + 3 + '4' + 'number' ,则操作按以下方式完成:

2 + 3 + '4' + 'number'
==> 5 + '4' + 'number'
// 数字 5 被隐式转换为字符串,然后连接起来
==> '54' + 'number'
==> '54number'

NaN 不等于任何其他类型,甚至它本身:

NaN == NaN  // false

7. 总结

上面的例子中,可以清楚地看到一些意想不到的结果:将 null 转换为数字时返回了 0,而将 undefined 转换为数字返回了 NaN。两个操作都应该返回 NaN,因为这两种值类型显然都不是有效的数字,将空字符串转换为数字时也返回了 0。

下面是 ECMAScript 规范中将数据类型转换为字符串的规则,清楚的解释了上面的异常现象:

fileOf7174.png

另外,在 ECMAScript 规范中,还提到一点:

fileOf7174.png

意思就是:为空或仅包含空格的 StringNumericLiteral 将转换为 +0。这也就解释了为什么将空字符串转换为数字时也返回了 0。

ECMAScript 规范: https://262.ecma-international.org/5.1/#sec-9.3

Symbol 类型转换

1. 创建并使用 Symbol 类型

我们可以使用 Symbol 函数来创建 Symbol 类型的值:

const mySymbol = Symbol();
console.log(typeof mySymbol); // 输出: "symbol"

上述代码创建了一个名为 mySymbol 的 Symbol 类型的值,并将其打印出来。注意到 typeof 操作符返回的结果是 "symbol",这表示该值是 Symbol 类型。

Symbol 类型的值可用于作为对象的属性名,以确保属性的唯一性。例如:

const mySymbol = Symbol("mySymbol");
const obj = {
  [mySymbol]: "Hello Symbol",
};

console.log(obj[mySymbol]); // 输出: "Hello Symbol"

在上述代码中,我们创建了一个带有描述符的 Symbol 值,并将其用作对象 obj 的属性名。通过使用方括号表示法,我们可以访问该属性并输出其值。

2. Symbol 转换为字符串、布尔值和数字

在 JavaScript 中,我们可以将 Symbol 类型的值转换为字符串、布尔值和数字类型。要将 Symbol 转换为字符串,可以使用 Symbol 值的 .toString() 方法或者调用 String() 函数。例如:

const mySymbol = Symbol("mySymbol");
console.log(mySymbol.toString()); // 输出: "Symbol(mySymbol)"
console.log(String(mySymbol)); // 输出: "Symbol(mySymbol)"

fileOf7174.png

在上述代码中,我们分别使用 .toString() 方法和 String() 函数将 Symbol 值转换为字符串。

然而,Symbol 类型的值不能直接与布尔值或数字进行转换,因为它们在不同的类型之间没有直接的关联。

3. 将其他类型转换为 Symbol

除了 Symbol 类型转换为其他类型,我们还可以将其他类型转换为 Symbol。为了将其他类型的值转换为 Symbol 类型,我们可以使用 Symbol() 函数并传递一个可选的描述符字符串作为参数:

const strSymbol = Symbol("string");
const boolSymbol = Symbol(Boolean(true));
const numSymbol = Symbol(Number(42));

在上述代码中,我们创建了三个不同的 Symbol 类型的值,并将分别将字符串、布尔值和数字类型的值转换为 Symbol 类型。

Symbol  只能进行显式转换,不能进行隐式转换。也就是说,Symbol不能被强制转换为字符串或数字,这样它们就不会被意外地用作本来应该表现为 Symbol 的属性。

const mySymbol = Symbol.for("mySymbol");
const str = String(mySymbol);

console.log(str);  // 'Symbol(mySymbol)'

当使用 console.log() 来打印 symbol 时,它之所以有效,是因为 console.log() 在 symbol 上调用了 String() 方法以创建可用的结果。

如果尝试直接使用字符串连接 symbol,它将抛出TypeError

const mySymbol = Symbol.for("mySymbol");
const sum = mySymbol + "";
console.log(sum);   // Uncaught TypeError: Cannot convert a Symbol value to a string

将 mySymbol 连接到字符串需要首先将 mySymbol 转换为字符串,并且在检测到强制转换时会抛出错误,从而阻止以这种方式使用它。

同样,我们不能将 symbol 强制转换为数字,所有数学运算符在与符号一起使用时都会引发错误:

const mySymbol = Symbol.for("mySymbol");
const factor = mySymbol / 2;
console.log(factor);   // Uncaught TypeError: Cannot convert a Symbol value to a number