本文深入解析JavaScript中将任意值转换为字符串的三种主要方式:value.toString()、"" + value以及String(value)。重点对比了后两者在原始值与对象值转换时的底层机制差异,特别是ToPrimitive(Number)与ToPrimitive(String)在调用valueOf与toString时的优先级区别,并给出了实际开发中的选型建议。
JavaScript中值转字符串的三种方法
译者注:前两天在看ES5的时候顺便出了一道题,今天看到这篇文章,刚好解释的很清楚,就翻译了一下。 在JavaScript中,主要有三种方法能让任意值转换为字符串。本文讲解了每种方法以及各自的优缺点。 1.转换字符串的三种方法 这三种将value转换为字符串的方法是: 1.value.toString() 2."" + value 3.String(value) 第一种方法存在的问题是,它不能把null和undefined转换为字符串。还有第二种和第三种方法,这两种方法的效果基本一样. •""+value: 使用加法运算符配合一个空字符串可以把任意值转换为字符串,我觉得这种方法代码的可读性很差,但相对String(value)来,还是有一些人更喜欢用这种转换方式. •String(value): 这种方法可读性更好,唯一的问题是,这种函数调用可能会迷惑一些人,尤其是那些熟悉Java的的程序员,因为String同时也是一个构造函数。要注意的是它作为普通函数和作为构造函数时的表现完全不同:
具体代码示例如下:
> String("abc") === new String("abc")
false
> typeof String("abc")
'string'
> String("abc") instanceof String
false
> typeof new String("abc")
'object'
> new String("abc") instanceof String
true 上述代码展示了String作为普通函数与构造函数时的行为差异。当String作为普通函数调用时,它返回一个原始字符串值;而作为构造函数(配合new)使用时,则返回一个String对象的实例。在JavaScript开发中,极少需要直接使用String对象实例,因此通常可以忽略其构造函数用法,但务必明确String作为类型转换函数的核心作用。
2.""+value 和 String(value)的细微差别
""+value与String()的细微差别
目前已知,加法运算符(+)与String()函数均能将“参数”转换为字符串。尽管在绝大多数场景下两者的转换结果一致,但它们在内部的转换机制上存在细微差别。
原始值转换为字符串机制
2.1 原始值转换为字符串的机制
这两种方法均依赖于引擎内部的ToString()操作来完成原始值的转换。所谓“内部操作”,指的是该逻辑在ECMAScript 5.1规范的第9.8节中定义,但ECMAScript语言本身并不直接暴露该接口供开发者调用。下表展示了ToString()对原始值的转换规则(见a0):
| 参数 | 结果 |
| undefined | "undefined" |
| null | "null" |
| 布尔值 | "true"或者"false" |
| 数字 | 数字作为字符串,比如"1.765" |
| 字符串 | 无需转换 |
2.2 将对象值转换为字符串
对象值转换为字符串机制
对于对象值的转换,这两种方法均遵循“先转换为原始值,再转换为字符串”的逻辑。然而,在将对象转换为原始值这一步骤中,加法运算符(+)默认使用内部的ToPrimitive(Number)操作(Date对象除外),而String()函数则使用ToPrimitive(String)操作。
• ToPrimitive(Number):该操作尝试将对象转换为原始值。首先调用obj.valueOf()。若返回值是原始值,则直接返回该原始值;若返回值仍是对象,则继续调用obj.toString()。若toString()返回原始值,则返回该值;否则,抛出TypeError异常。
• ToPrimitive(String):逻辑与上述类似,区别在于优先调用obj.toString()方法,而非obj.valueOf()。
通过以下对象示例,可以直观看到两者的执行顺序差异:
具体代码实现如下:
var obj = {
valueOf: function () {
console.log("valueOf");
return {}; // 非原始值,继续执行
},
toString: function () {
console.log("toString");
return {}; // 非原始值,继续执行
}
};
// 执行结果:
> "" + obj
valueOf
toString
TypeError: Cannot convert object to primitive value
> String(obj)
toString
valueOf
TypeError: Cannot convert object to primitive value 2.3 结果通常都相同
上述差异在实际开发中极少遇到,原因在于:大多数对象默认继承自Object的valueOf()方法,该方法直接返回对象本身(即非原始值)。
验证代码如下:
> var x = {}
> x.valueOf() === x
true 因此,ToPrimitive(Number)通常会跳过valueOf()(因其返回对象本身),转而调用toString(),这使得其表现与ToPrimitive(String)几乎完全一致。然而,若该对象是Boolean、Number或String的包装对象实例,其valueOf()方法会返回被包装前的原始值。此时,两种操作的执行路径如下:
• ToPrimitive(Number):返回对象的valueOf()方法结果(即被包装前的原始值),再对该原始值执行ToString()操作。
• ToPrimitive(String):返回对象的toString()方法结果(即在被包装前的原始值上执行ToString()操作)。
尽管路径不同,最终返回的字符串结果通常是一致的。
3.结论
转换方式的选择建议
那么,在实际开发中应如何选择转换方式?若能确保值永远不会是null或undefined,可以使用value.toString()进行转换。否则,在"" + value与String(value)之间,两者皆可,取决于个人偏好。从代码可读性与明确性的角度考虑,本人更倾向于使用String(value)。
4.相关文章
- JavaScript values: not everything is an object [原始值和对象值的区别]
- What is {} + {} in JavaScript? [解释了+运算符的工作原理]
- String concatenation in JavaScript [怎样才能更好的连接多个字符串]