Es6 模板字符串及新增方法

模板字符串(template string) 是增强版的字符串,用反引号 ( ` ) 标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

// 普通字符串
console.log(`In JavaScript \n is a line-feed.`);
// 多行字符串
console.log(`In JavaScript this is 
not legal.`);
// 字符串中嵌入变量
let name = "baby";
console.log(`Hi ${name},`);

如果在模板字符串中需要使用反引号,则前面要用反斜杠转义。

let greeting = `\`Yo\` World~`;
console.log(greeting);  // `Yo` World~

如果使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出中。

console.log(`
  <ul>
    <li>first</li>
    <li>second</li>
  </ul>
`);

如果不想要这些换行,可以使用 trim 方法消除它。

console.log(`
  <ul>
    <li>first</li>
    <li>second</li>
  </ul>
`.trim());

模板字符串嵌入变量,需要将变量名写在 ${} 之中。

let x = 1;
let y = 2;
console.log(`${x} + ${y} = ${x + y}`);  // 1 + 2 = 3
console.log(`${x} + ${y * 2} = ${x + y * 2}`);  // 1 + 4 = 5
let obj = {x: 1, y: 2};
console.log(`${obj.x + obj.y}`);  // 3

模板字符串中还能调用函数。

function fn () {
  return "or";
}
console.log(`foo ${fn()} bar`);  // foo or bar

如果模板字符串中的变量没有声明,将报错。

let msg = `Hello, ${place}`;  // Error

由于模板字符串的大括号内部,就是执行 JavaScript 代码,因此如果大括号内部是一个字符串,将会原样输出。

console.log(`Hello ${'World'}`);  // Hello World

模板字符串的功能,不仅仅是上面这些。它可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为 “标签模板” 功能(tagged template)。

alert`123`;
// 等同于
alert(123);

字符串新增方法

String.fromCharCode()

Es5 提供 String.fromCharCode() 方法,用于从 Unicode 码点返回对应字符,但是这个方法不能识别码点大于 0xFFFF 的字符。

console.log(String.fromCharCode(96));  // "`"
console.log(String.fromCharCode(0x20BB7));  // ஷ

上面代码中,String.fromcharCode() 不能识别大于 0xFFFF 的码点,所以 0x20BB7 就发生了溢出,最高位 2 被舍弃了,最后返回码点 U + 0BB7 对应的字符,而不是码点 U + 20BB7 对应的字符。

Es6 提供 String.fromCodePoint() 方法,可以识别大于 0xFFFF 的字符,弥补了 String.fromCharCode() 方法的补助。在作用上,正好与下面的 codePointAt() 方法相反。

console.log(String.fromCodePoint(0x20BB7));  // "𠮷"

如果 String.fromCodePoint() 对象有多个参数,则它会被合并一个字符串返回。

console.log(String.fromCodePoint(0x78, 0x1f680, 0x79));
console.log(String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y');  // true

注意,fromCodePoint() 方法定义在 String 对象上,而 codePointAt 方法定义在字符串的实例对象上。

String.raw()

Es6 还为原生的 String 对象,提供了一个 raw() 方法。该方法返回一个斜杠都被转义(斜杠前面再加上一个斜杠)的字符串,往往用于模板字符串的处理办法。

console.log(String.raw`Hi\n${2 + 3}!`);  // 实际返回 "Hi\\n5!",显示的是转义后的结果 "Hi\n5!"

如果元字符串的斜杠已经转义,那么 String.raw() 会进行再次转义。

console.log(String.raw`Hi\\n`);  // Hi\\n
console.log(String.raw`Hi\\n` === "Hi\\\\n");  // true

String.raw() 方法可以作为处理模板字符串的基本办法,它会将所有变量替换,而且对斜杠进行转义,方便下一步作为字符串来使用。

实例方法:codePointAt()

JavaScript内部,字符串以 UTF - 16 的格式储存,每个字符固定为 2 个字节。对于那些需要 4 个字节储存的字符(Unicode 码点大于 0xFFFF 的字符),JavaScript 会认为它们是两个字符。

{
  let s = "𠮷";
  console.log(s.length);  // 2
  console.log(s.charAt(0));  // �
  console.log(s.charAt(1));  // �
  console.log(s.charCodeAt(0));  // 55362
  console.log(s.charCodeAt(1));  // 57271
}

上代码中,汉字 “𠮷”(注意,这个字不是 “吉祥” 的 "吉")的码点是 0x20BB7,UTF-16 编码为 0xD842 0xDFB7(十进制为 55362 57271),需要 4 个字节储存。对于这种 4 个字节的字符,JavaScript 不能正确处理,字符串长度会误判为 2,而且 charAt() 方法无法读取整个字符,charCodeAt() 方法只能分别返回前两个字节和后两个字节的值。

Es6 提供了 codePointAt() 方法,能够正确处理 4 个字节存储的字符,返回一个字符的码点。

{
  let s = "𠮷a";
  console.log(s.codePointAt(0));  // 134071
  console.log(s.codePointAt(1));  // 57271
  console.log(s.codePointAt(2));  // 97
}

codePointAt() 方法的参数,是字符在字符串中的位置(从 0 开始)。上面代码中,JavaScript 将 "𠮷a" 视为三个字符,codePointAt 方法在第一字符上,正确地认识了 "𠮷",返回了它的十进制码点 134071(即十六进制的 20BB7)。

codePointAt() 方法会正确返回 32 位的 UTF-16 字符的码点。对于那些两个字节储存的常规字符,它的返回结果与 charCodeAt() 方法相同。

codePointAt() 方法返回的是码点的十进制值,如果想要十六进制的值,可以使用 toString() 方法转换一下。

{
  let s = "𠮷a";
  console.log(s.codePointAt(0).toString(16));  // "20bb7"
  console.log(s.codePointAt(2).toString(16));  // "61"
}

实例方法:normalize()

许多欧美语言有语调音符和重音符号。为表示,Unicode 提供了两种方法。

// 1、直接代重音符号的字符
console.log('\u01D1');  // Ǒ
// 2、合成字符
console.log('\u004F\u030C');  // Ǒ
console.log('\u01D1' === '\u004F\u030C');  // false。这两种表示方法,在视觉和语义上都等价,但是 JavaScript 不能识别
console.log('\u01D1'.length, '\u004F\u030C'.length);  // 1 2。JavaScript 将合成字符视为两个字符,导致两种表示方法不相等。

Es6 提供字符串实例的 normalize() 方法,用来将字符串的不同表示方统一为同样的形式,这称为 Unicode 正规化。

console.log('\u01D1'.normalize() === '\u004F\u030C'.normalize());  // true

实例方法:includes(),startsWith(),endsWith()

JavaScript 只有 indexOf 方法,可以用来确定一个字符串是否包含在另一个字符串中。Es6 又提供了三种新方法。

  • includes(): 返回布尔值,表示是否找到了参数字符串。
  • startsWith(): 返回布尔值,表示参数字符串是否在原字符串的头部。
  • endsWith(): 返回布尔值,表示参数字符串是否在原字符串的尾部。
{
  let s = "Hello World~";
  console.log(s.startsWith('Hello'));  // true
  console.log(s.endsWith('~'));  // true
  console.log(s.includes('o'));  // true
}

这三个方法都支持第二个参数,表示开始搜索的位置。

{
  let s = "Hello World~";
  console.log(s.startsWith('World', 6));  // true
  console.log(s.endsWith('Hello', 5));  // true
  console.log(s.includes('Hello', 6));  // false
}

上面代码表示,使用第二个参数 n 时,endsWith 的行为与其他两个方法有所不同。它针对前 n 个字符,而其他两个方法对从第 n 个位置直到字符串结束。

实例方法:repeat()

repeat() 方法返回一个新字符串,表示将原字符串重复 n 次。

console.log('x'.repeat(3));  // "xxx"
console.log('hello'.repeat(2));  // "hellohello"
console.log('na'.repeat(0));  // ""

参数如果是小数,会被取整。

console.log('na'.repeat(2.9));  // "nana"

如果 repeat 的参数是负数或者 Infinity,会报错。

console.log('na'.repeat(Infinity));  // error
console.log('na'.repeat(-1));  // error

但是,如果参数是 0 到 -1 之间的小数,则等同于 0,这是因为会先进性取整运算。0 到 -1 之间的小数,取证后等于 -0,repeat 视为 0。

console.log('no'.repeat(-0.9));  // ""

参数 NaN 等同于 0。

console.log('na'.repeat(NaN));  // ""

如果 repeat() 的参数是字符串,则会先转换为数字。如果 repeat() 的参数是字符串,则会先转换为数字。

console.log('na'.repeat('na'));  // ""。 "na" ==> Number('na') ==> NaN == 0
console.log('na'.repeat('3'));  // "nanana"

实例方法:padStart(),padEnd()

Es2017 引入字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart() 用于头部补全,padEnd() 用于尾部补全。

padStart() 和 padEnd() 一共接收两个参数,第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串。

{
  console.log('x'.padStart(5, 'ab'));  // "ababx"
  console.log('x'.padStart(4, 'ab'));  // 'abax'
  console.log('x'.padEnd(5, 'ab'));  // "xabab"
  console.log('x'.padEnd(4, 'ab'));  // "xaba"
}

如果原字符串的长度,等于或大于最大长度,则字符串补全不生效,返回原字符串,

{
  console.log('xxx'.padStart(2, 'ab'));  // "xxx"
  console.log('xxx'.padEnd(2, 'ab'));  // "xxx"
}

如果用来补全的字符串与原字符串,两者的长度之和超过了最大长度,则会截取超出位数的补全字符串。

{
  console.log('abc'.padStart(10, '0123456789'));  // "0123456abc"
}

如果忽略第二个参数,默认使用空格补全长度。

{
  console.log('x'.padStart(4));  // "   x"
  console.log('x'.padEnd(4));  // "x   "
}

padStart() 的常见用途是为数值补全指定位数。

{
  console.log('1'.padStart(10, '0'));  // "0000000001"
  console.log('12'.padStart(10, '0'));  // "0000000012"
  console.log('123456'.padStart(10, '0'));  // "0000123456"
}

另一个用途是提示字符串格式。

{
  console.log('12'.padStart(10, 'YYYY-MM-DD'));  // "YYYY-MM-12"
  console.log('09-12'.padStart(10, 'YYYY-MM-DD'));  // "YYYY-09-12"
}

实例方法:timeStart(),timeEnd()

Es2019 对字符串实例新增了 trimStart() 和 trimEnd() 这两个方法。它们的行为与 trim() 一致,trimStart() 消除字符串头部的空格,trimEnd() 消除尾部的空格。它们返回的都是新字符串,不会修改原字符串。

trimStart() 只消除头部的空格,保留尾部的空格。trimEnd() 也是类似行为。

{
  const s = '  abc  ';
  console.log(s.trim());  // "abc"
  console.log(s.trimStart());  // "abc  "
  console.log(s.trimEnd());  // "  abc"
}

除了空格键,这两个方法字符串头部(或尾部)的 tab 键、换行符等不可见的空白符也有效。

浏览器还部署了额外的两个方法,trimLeft() 是 trimStart() 的别名,trimRight() 是 trimEnd() 的别名。


Es5字符串方法

String.fromCharCode()

String.fromCharCode(Unicode); 从字符编码创建一个字符串

实例方法:toString()

s.toString(args); 返回转换后的字符串。

实例方法:charAt()

s.charAt(number); 返回指定位置的字符。

实例方法:charCodeAt()

s.charCodeAt(number); 返回指定位置的字符编码。

实例方法:concat()

s.concat(string); 拼接字符串。

实例方法:indexOf()

s.indexOf(string); 方法返回某个指定的字符串值在字符串中首次出现的位置。参数1:必需。规定需检索的字符串;参数2:可选的整数参数。规定在字符串中开始检索的位置。它的合法取值是 0 到 stringObject.length - 1。如省略该参数,则将从字符串的首字符开始检索。

实例方法:lastIndexOf()

s.lastIndexOf(string); 从后向前搜索字符串。

实例方法:slice()

s.slice(start,end); 截取字符串,返回截取后字符串。1个参数,从第几个开始截取到最后;2个参数,从第几个截取到第几个。

实例方法:split()

s.split(''); 把字符串分割成数组。不写参数就会分成一个数组,有参数是根据参数字符串分割成指定数组。

实例方法:substr()

s.substr(start,len); 从指定索引提取字符串中指定数目的字符串,1个参数,从第几个开始截取到最后;2个参数,从第几个截取几个。

实例方法:substring()

s.substring(start,end); 提取字符串中两个指定的索引之间的字符。

实例方法:toLowerCase()

s.toLowerCase(string); 把字符串转换为小写。

实例方法:toUpperCase()

s.toUpperCase(string); 把字符串转换为大写。

实例方法:sub()

s.sub() 把字符串显示为下标。

实例方法:sup

s.sup(); 把字符串显示为下标。

实例方法:fontcolor()

s.fontcolor(); 使用指定的颜色来显示字符串。

实例方法:fontsize()

s.fontsize(); 使用指定的尺寸来显示字符串。

实例方法:match()

s.match(); 找到一个或多个正则表达式的匹配,返回一个数组对象,来存储这个字符的信息。

实例方法:replace()

s.replace(); 替换与正则表达式相匹配的值。

实例方法:search()

s.search(); 检索与正则表达式小匹配的值,返回字符索引。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容