字符串原始值和字符串对象
注意,JavaScript 区分 String
对象和原始字符串值(Boolean 和 Number 也是如此)。
字符串字面量(使用单引号或者双引号表示)和从非构造函数上下文中的 String
调用返回的字符串(即在不使用 new 关键字的情况下调用)是原始字符串。在要对原始字符串调用方法或者发生属性查找的上下文中,JavaScript 将自动的包装原始字符串并调用方法或在包装对象上执行属性查找。
const strPrim = "foo"; // A literal is a string primitive
const strPrim2 = String(1); // Coerced into the string primitive "1"
const strPrim3 = String(true); // Coerced into the string primitive "true"
const strObj = new String(strPrim); // String with new returns a string wrapper object.
console.log(typeof strPrim); // "string"
console.log(typeof strPrim2); // "string"
console.log(typeof strPrim3); // "string"
console.log(typeof strObj); // "object"
警告: 你应该发现你自己很少使用 String
构造函数。
使用 eval() 时,字符串原始值和 String
对象也会给出不同的结果。传递给 eval
的原始值被当作源代码处理;而 String
对象则被当作对象处理,返回对象。例如:
const s1 = "2 + 2"; // creates a string primitive
const s2 = new String("2 + 2"); // creates a String object
console.log(eval(s1)); // returns the number 4
console.log(eval(s2)); // returns the string "2 + 2"
由于上述原因,当一段代码在需要使用基本字符串的时候却使用了 String
对象就会导致执行失败(虽然一般情况下程序员们并不需要考虑这样的问题)。
String
对象始终可以使用 valueOf() 方法将其转换为它的原始值(字面量)。
console.log(eval(s2.valueOf())); // returns the number 4
字符串强制转换
许多期望字符串的内置操作首先将它们的参数强制转换为字符串(这也就是为什么 String
对象的行为类似于字符串原始值)。这些操作可以总结为以下几点:
- 字符串按原样返回。
- undefined 转换成
"undefined"
。 - null 转换成
"null"
。 true
转换成"true"
;false
转换成"false"
。- 使用与 toString(10) 相同的算法转换数字。
- 使用与 toString(10) 相同的算法转换 BigInt。
- Symbol 抛出 TypeError。
- 首先,对象通过依次调用 [@@toPrimitive]()(hint 为
"string"
)、toString()
和valueOf()
方法将其转换为原始值。然后将生成的原始值转换为一个字符串。
有几种方法可以在 JavaScript 中实现几乎相同的效果。
- 模板字符串:
`${x}`
为嵌入的表达式执行上面的字符串强制转换步骤。 - String() (en-US) 函数:
String(x)
使用相同的算法去转换x
,只是 Symbol 不会抛出 TypeError,而是返回"Symbol(description)"
,其中description
是对 Symbol 的描述。
const sym = Symbol("example");
`${sym}`; // TypeError: Cannot convert a Symbol value to a string
"" + sym; // TypeError: Cannot convert a Symbol value to a string
"".concat(sym); // TypeError: Cannot convert a Symbol value to a string
const sym = Symbol("example");
String(sym); // "Symbol(example)"
根据你使用的情况,你可能想要使用 `${x}`
(模拟内置行为)或 String(x)
(处理 symbol 值而不抛出错误),但你不应该使用 "" + x
。