字符串在 任何编程语言中是常见的,也是常用的,因此掌握 String 类型的概念和使用亦重要。
String 类型
String(字符串)数据类型表示零个或多个16位 Unicode 字符序列,字符串可以使用 双引号 "str content", 单引号 'str content' 或 反引号(也叫字符串模板,可以使用 ${变量} 来引用变量的值)
// 注意⚠️: 这些符号需要成队出线,以相同的符号开始就要以相同的符号结束
const str1 = "hello";
const str2 = ", world"
const helo = `${str1}${world} other something`
字符字面量
如下字符串数据类型有特殊的含义,可以用在字符字面量中,详情看下图:
这些字符字面量可以出现在字符串中的任意位置,且可以作为单个字符被解释
const { log } = console;
log('str: \u03a3'); // str: Σ, 03a3 被 \u 转译了
log('h\ne\ne\nl'); // hello 被换行展示了
log('\u03a3'.length); // 1, length 是显示转译后的长度
字符串的特点
字符串是不可变的(immutable),意味着他们一旦被创建,值就不能变化了,如果要修改某个变量中的字符串值,必须先销毁原始的字符串,然后将包含新值的另一个字符串保存到该变量
let lang = "java"; // “java” 被创建了,因此 java 不会变化了
lang = lang + "script"; // 这里是创建了一个新的字符 "javascript",然后销毁了 java 和 script 两个字符串,并将新创建的 javascript 赋值给了 lang 变量,因此字符串是不可变的
转化为字符串的方式
- toString(radix?: number): string; radix 只用于 将数值类型转换为 对应 radix 进制的字符串,不传递则转换为 10 进制,但是 null 和 undefined 没有这个方法,其他值均有这个方法
- 空字符串 + variable ; 表示使用一个空字符串加上变量就会 将变量转化为对应的字符串
- String(value); 会将 value 转化为字符串
- 模板字符串(也叫做模板字面量)
const { log } = console;
const numberVar = 11;
const nullVar = null;
const undefinedVar = undefined;
const obj = { name: 'kj' };
// 注意: 如果是直接 11.toString();会报错 Uncaught SyntaxError: Invalid or unexpected token
/// 使用变量来 调用 toString()
log(numberVar.toString());
log(numberVar.toString());
// // TypeError: Cannot read properties of null (reading 'toString')
// log(nullVar.toString());
// // TypeError: Cannot read properties of undefined (reading 'toString')
// log(undefinedVar.toString());
log(obj.toString()); // [object Object], 你可以给对象重写 toString() 方法
/**
* 使用 String(value) 构造函数将 value 转化为 字符串
* 这样的好处是解决了 null 和 undefined 没有 toString() 函数的烦恼
*/
log(String(numberVar)); // 11
log(String(nullVar)); // null
log(String(undefinedVar)); // undefined
log(String(obj)); // [object Object]
/**
* 使用 ""(或 ''、``) + value 将 value 变为字符串
*/
log('' + numberVar); // 11
log('' + nullVar); // null
log('' + undefinedVar); // undefined
log('' + obj); // [object Object]
/**
* `${value}` 模板插值将 value 转化为字符串 差不多就是 String(value) 的变种,但是当 value 有 toString() 会调用它的 toString() 方法
*/
log(`${numberVar}`); // 11
log(`${nullVar}`); // null
log(`${undefinedVar}`); // undefined
log(`${obj}`); // [object Object]
注意: ${value} 模板插值将 value 转化为字符串 差不多就是 String(value) 的变种,但是当 value 拥有 toString 的时候,会优先调用其 toString() 方法
const { log } = console;
const objWith2String = {
name: 'jakequc',
age: 23,
toString() {
return `my name: ${this.name}, age: ${this.age}`;
},
};
log(`${objWith2String}`); // my name: jakequc, age: 23
模板字面量标签函数
标签函数是一个常规函数,标签函数接受到的参数依次是原始字符串数组 和 对每个表达式求职的结果。可以自定义标签函数的返回值
const { log } = console;
/**
* @param {string[]} strings 原始字符串数组
* @param {string} expressRes1 第一个表达式求职的结果
* @param {string} expressRes2 第二个表达式求值的结果
* @param {string} expressRes3 第三个表达式求职的结果
*/
function tagFn(strings, expressRes1, expressRes2, expressRes3) {
log(strings, expressRes1, expressRes2, expressRes3); // [ '', '+', '+', '' ] 1 12 123
return [expressRes1, expressRes2, expressRes3].reduce(
(pre, curr) => pre + curr,
'',
);
}
const str1 = 1,
str2 = str1 + '2',
str3 = `${str2}3`;
log(tagFn`${str1}+${str2}+${str3}`); // 最终会返回 “1” + “12” + “123” = 112123
因为表达式参数的数量是可变的,所以应该使用剩余操作符(rest operator) 将他们收集到一个数组中
const { log } = console;
/**
* @param {string[]} strings 原始字符串数组
* @param {any} expressList 第一个表达式求职的结果
*/
function tagFn(strings, ...expressList) {
log(strings, expressList); // [ '', '+', '+', '' ] [ 1, '12', '123' ]
return expressList.reduce((pre, curr) => pre + curr, '');
}
const str1 = 1,
str2 = str1 + '2',
str3 = `${str2}3`;
log(tagFn`${str1}+${str2}+${str3}`); // 最终会返回 “1” + “12” + “123” = 112123
const a = 6;
const b = 9;
function zipTag(strings, ...expressions) {
return (
strings[0] + expressions.map((e, i) => `${e}${strings[i + 1]}`).join('')
);
}
const untaggedResult = `${a} + ${b} = ${a + b}`;
const taggedResult = zipTag`${a} + ${b} = ${a + b}`;
console.log(untaggedResult); // "6 + 9 = 15"
console.log(taggedResult); // "6 + 9 = 15"
原始字符串 String.raw`str`
使用模板字面量也可以通过 String.raw 直接获取原始的模板字面量内容(如换行符或 Unicode 字符),而不是被转化后的字符表示。
const { log } = console;
log('\u00A9'); // log: © , 因为 \u00A9 对应的字符表示是 © (打印的是表现形式)
// 如果要 log 出 \u00A9 便需要用到 String.raw
log(String.raw`\u00A9`); // log: \u00A9 (打印的是编写形式)
注意⚠️:使用 String.raw 后边带的是 模板字符串(或模板字面量及 ``,这对反字符串中间是任意的字符串,String.raw`anystr`返回的是 anystr 的原始内容(即不包含其原来的表现形式,只是获取其编写形式(即原始字符串))