ECMAScript.6 String相关
Unicode
{}
JavaScript字符以UTF-16的格式储存,允许使用\uxxxx表示一个字符,其中xxxx表示字符的Unicode码点。这个表示法只限于 “\u0000~\uFFFF”之间的字符。
console.log('\u0061'); // "a"
// "𠮷"
console.log('\u20bb7'); // "₻7"
// 上述代码JavaScript会将其理解成 \u20bb+7
// 替代方案
console.log('\ud842\udfb7'); // "𠮷"
ES6中 将码点放入大括号内,加强了对 Unicode 的支持。
console.log('\u{20bb7}'); //"𠮷"
console.log('\u{d842}\u{dfb7}'); //"𠮷"
console.log('\u{20bb7}' === '\u{d842}\u{dfb7}');// true
console.log('\u{7a}' === '\u007a'); //true
codePointAt
JavaScript内部,每个字符固定为2个字节,但是这个表示法只限于 “\u0000~\uFFFF”之间的字符,Unicode码点大于0xFFFF的字符就需要4个字节储存的字符,JavaScript会认为它们是两个字符.。
let text1 = '\u0061';
let text2 = '\ud842\udfb7';
console.log(text1); // "a"
console.log(text1.length); // 1
console.log(text2); //"𠮷"
console.log(text2.length); // 2
es6之前可以使用charAt()和charCodeAt()访问字符串,其中charAt()方法返回给定位置的那个字符。charCodeAt()则返回给定位置的那个字符的字符编码。
let text1 = "a";
console.log(text1.charAt(0)); // "a"
console.log(text1.charCodeAt(0)); // 97
console.log(text1.charCodeAt(0).toString(16)); // "61"
let text2 = "𠮷";
console.log(text2.length); // 2
console.log(text2.charAt(0)); // ""
console.log(text2.charAt(1)); // ""
console.log(text2.charCodeAt(0)); // 55362
console.log(text2.charCodeAt(1)); // 57271
console.log(text2.charCodeAt(0).toString(16)); // "d842"
console.log(text2.charCodeAt(1).toString(16)); // "dfb7"
上述代码中”𠮷”的码点在”20bb7”,超出了”FFFF”,故需要4个字节存储,对于对于这种情况JavaScript会误判字符串长度为2。charAt方法失效。charCodeAt也只能返回前两个及后两个字节的值。
var s = '𠮷a';
console.log(s.length);
console.log(s.codePointAt(0)); // 134071
console.log(s.codePointAt(1)); // 57271
console.log(s.codePointAt(2)); // 97
console.log(s.charCodeAt(0)); // 55362
console.log(s.charCodeAt(1)); // 57271
console.log(s.charCodeAt(2)); // 97
上述代码中可以看出JavaScript依旧视s为三个字符,但使用codePointAt后第一个字符可以识别“𠮷”,第二个及第三个字符返回值与charCodeAt相同。
// 转换为16进制
var s = '𠮷a';
console.log(s.codePointAt(0).toString(16)); // "20bb7"
console.log(s.codePointAt(1).toString(16)); // "dfb7"
console.log(s.codePointAt(2).toString(16)); // "61"
console.log(s.charCodeAt(0).toString(16)); // "d842"
console.log(s.charCodeAt(1).toString(16)); // "dfb7"
console.log(s.charCodeAt(2).toString(16)); // "61"
console.log('\u{20bb7}' === '\ud842\udfb7'); //true
String.fromCodePoint()
ES6提供了String.fromCodePoint方法,可以识别大于0xFFFF的字符
var txt = "𠮷";
console.log(String.fromCodePoint(txt.codePointAt(0))); // "𠮷"
normalize()
许多欧洲语言有语调符号和重音符号。Unicode提供两种方式表达,一种是直接提供带重音符号的字符,比如Ǒ(\u01D1)。另一种是两个字符合成一个字符,比如Ǒ(\u004F\u030C)。他们在语义和视觉上是等价的,但JavaScript不能识别。
console.log('\u01D1'==='\u004F\u030C') //false
console.log('\u01D1'.length);
// 1
console.log('\u004F\u030C'.length);// 2
ES6提供字符串实例的normalize()方法 normalize函数的参数有四个可选值:’NFC(默认参数)’(标准等价合成)、’NFD’(标准等价分解)、’NFKC’(兼容等价合成)、’NFKD’(兼容等价分解)
console.log('\u01D1'.normalize()==='\u004F\u030C'.normalize())
u修饰符
ES6 对正则表达式添加了u修饰符,可以正确处理四个字节的 UTF-16 编码。
let text = '\ud842\udfb7'; //"𠮷"
let reg1 = /^\ud842/;
let reg1u = /^\ud842/u;
// wrong
console.log(reg1.test(text)); // true
// right
console.log(reg1u.test(text)); // false
// 同理希望匹配 text为换行符以外的任意单个字符
let text = '\ud842\udfb7'; //"𠮷"
let reg2 = /^.$/;
let reg2u = /^.$/u;
// wrong
console.log(reg2.test(text));
// right
console.log(reg2u.test(text));
// 在正则表达式中使用大括号表示Unicode 字符时,这种表示法必须加上u修饰符,否则会当做量词处理。
/\u{20bb7}/u.test('𠮷') // true
/\u{20bb7}/.test('𠮷') // false
// 匹配码点大于0xFFFF的 Unicode 字符还需注意
// 使用量词匹配
console.log(/a{2}/.test('aa') ); // true
console.log(/a{2}/u.test('aa')); // true
console.log(/𠮷{2}/.test('𠮷𠮷') ); // false
console.log(/𠮷{2}/u.test('𠮷𠮷')); // true
// 使用预定义字符匹配
// 匹配非空字符串
console.log(/^\S$/.test('𠮷')); //false
console.log(/^\S$/u.test('𠮷')); //true
计算字符长度
function codePointLength(text){
let result = text.match(/[\s\S]/gu);
return result ? result.length : 0;
}
console.log(codePointLength("abc")); // 3
console.log("𠮷bc".length); // 4
console.log(codePointLength("𠮷bc")); // 3
y
y叫做‘粘连’(sticky)修饰符,y修饰符与g类似都是全局匹配,不同之处在于g修饰符只要剩余位置中存在匹配就可以,但y则必须确保匹配从剩余位置的第一个位置开始。
var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;
console.log(r1.exec(s)); //["aaa"]
console.log(r2.exec(s)); //["aaa"]
console.log(r1.exec(s)); //["aa"]
console.log(r2.exec(s)); //null
var r = /a+_/y;
console.log(r.exec(s)); //["aaa_"]
console.log(r.exec(s)); //["aa_"]
console.log(r.exec(s)); //null
下面的代码lastIndex指的是每次搜索的开始位置,g修饰符从这个位置开始向后搜索直至发现匹配为止,y同时遵循lastIndex属性但必须要求在lastIndex指定的位置发现匹配。
// g lastIndex
const REGEX = /a/g;
console.log(REGEX.lastIndex); //0
REGEX.lastIndex = 2;
const match = REGEX.exec('xaya');
console.log(match); //["a"]
console.log(match.index);//3
console.log(REGEX.lastIndex);//4
console.log(REGEX.exec('xaya'));//null
// y lastIndex
const REGEX = /a/y;
// wrong
REGEX.lastIndex = 2;
const match = REGEX.exec('xaya');
console.log(match); // null 从y开始
// right
REGEX.lastIndex = 3;
const match = REGEX.exec('xaya'); //["a"]
console.log(match.index);//3
console.log(REGEX.lastIndex);//4
console.log(REGEX.exec('xaya'));//null
// sticky属性
var r = /hello\d/y;
console.log(r.sticky); //true
let re = /ab/g
console.log(re.flags) // 'g'
console.log(re.source) // 'ab'
template literals(模板字符串)
反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
基础语法
let message = `Hello world!`;
console.log(message); //"Hello world!"
console.log(typeof message);//"string"
console.log(message.length);//12
let number = `1`;
console.log(typeof number); //"string"
// 如果想添加“`”,添加转译字符
let message = `\`Hello\` world!`;
console.log(message); //"`Hello` world!"
console.log(typeof message);//"string"
console.log(message.length);//14
多行文本
// 使用 "\" 将js 代码折行
var message = "Multiline \
string";
console.log(message); // "Multiline string"
// \n
var message = "Multiline \n\
message";
console.log(message); //"Multiline
// message"
// join
var message = ['Multiline','string'].join('\n');
console.log(message) //"Multiline
// message"
// +
var message = 'Multiline \n' + 'string';
console.log(message); //"Multiline
// message"
// `
let message = `Multiline
string`;
console.log(message);
// 使用trim方法使首行末行缩进
let html = `
<div>
<h1>title<h1>
</div>
`;
console.log(html);
// "
// <div>
// <h1>title<h1>
// </div>
// "
console.log(html.trim());
"<div>
<h1>title<h1>
</div>"
嵌入变量
// 使用 ${}嵌入变量
let name = "Nicholas";
let message = `Hello,${name}`;
console.log(message); //"Hello,Nicholas"
// 计算
let count = 10,
price = 0.25,
message = `${count} items cost ${(count*price).toFixed(2)}`;
console.log(message); // "10 items cost 2.50"
// dom
var data = [{
id: '201706',
name: '二零一七年六月'
}, {
id: '201707',
name: '二零一七年七月'
}];
var $body = $('body');
var template = '',result = '';
data.forEach(function(obj){
template += `<li>${obj.name}</li>`
})
result = `<ul>${template}</ul>`;
$body.append($(result));
标签模板
Template Strings(模板字符串)是以整体为单位进行即时计算,对模板字符串的操控能力有限,但Tagged Template Strings则可以增强操控能力。
var x = 1, y = 2;
var passthru = function (literals,...substitutions){
let result = '';
console.log(literals); //["hello", ":", ""]
console.log(substitutions);//[1, 3]
substitutions.forEach(function(val,i){
result+=literals[i] + 'tagged';
result+=substitutions[i];
})
result+=literals[literals.length -1];
return result
};
console.log(`hello${x}:${y+1}`);// "hello1:3"
console.log(passthru`hello${x}:${y+1}`);//"hellotagged1:tagged3"
includes(),startsWith(),endsWith()
在es6之前通常使用indexOf确定一个字符串是否在另一个字符串中。es6新增includes(),startsWith(),endsWith()三个方法,这三个方法有两个参数,第一个为参数字符串,第二个为从哪个位置开始搜索(除了endsWith)。
- includes:表示在源字符串中是否找到了参数字符串
- startsWith:表示在源字符串头部是否找到了参数字符串
- endsWith:表示在源字符串尾部是否找到了参数字符串,但第二个参数指的是针对前n个字符开始查找。
var s = 'Hello World!';
console.log(s.startsWith('Hello')); //true
console.log(s.endsWith('!')); //true
console.log(s.includes('W')); // true
console.log(s.startsWith('World',6)); // true
console.log(s.startsWith('Hello',5)); // true
console.log(s.includes('H',1)); // false
repeat()
该方法接受一个参数n重复源字符串n次。
// 单个字符
console.log('x'.repeat(2)); // "xx"
// 字符串
console.log('world'.repeat(3)); // "worldworldworld"
// 参数为0 结果为空字符串
console.log('hello'.repeat(0)); // ""
// 负数 -1 > n
console.log('hello'.repeat(-2)); // throw error RangeError
// 如果 -1 < n < 0 结果为空字符串
console.log('hello'.repeat(-0.2)); // ""
// Infinity
console.log('hello'.repeat(Infinity));// throw error RangeError
// NaN
console.log('hello'.repeat(NaN)); // ""
// 如果是字符串,会将其转换成数字然后执行
console.log('hello'.repeat('qq')); // ""
console.log('hello'.repeat('3')); // "hellohellohello"
padStart()、padEnd()
如果某个字符串不够指定长度,会在头部或尾部补全,padStart()用于头部补全,padEnd()用于尾部补全。第一个参数为补全后字符串的长度,但二个参数为使用什么字符串补全,如果第二个参数没有默认为空格。
console.log('x'.padStart(5,'ab'));// 'ababx'
console.log('x'.padStart(4,'ab'));// 'abax'
console.log('x'.padStart(4)); // ' x'
console.log('x'.padEnd(5,'ab'));// 'xabab'
console.log('x'.padEnd(4,'ab'));// 'xaba'
console.log('x'.padEnd(4)); //'x '