文章目錄
  1. 1. 更好的Unicode支持
    1. 1.1. codePointAt()
    2. 1.2. String.fromCodePoint()
    3. 1.3. 编码非BMP字符
    4. 1.4. 正则表达式u修饰符
  2. 2. 新增的String方法
    1. 2.1. includes()
    2. 2.2. startsWith()
    3. 2.3. endsWith()
    4. 2.4. repeat()
  3. 3. 正则表达式修饰符y

ES6中对字符串进行了很多扩展,包括加强了Unicode的支持、

更好的Unicode支持

ES6之前,JavaScript的字符串是完全基于16位字符编码的想法。所有字符串的属性和方法,例如:lengthcharAt(),都是基于16位序列代表单个字符的想法。ES5还允许Javascript引擎决定使用哪种编码方式,UCS-2UTF-16

对于Unicode的既定目标,保持在16位是不可能的为全世界的每一个字符提供一个全局唯一的标识符。这些全局唯一标志服被称之为code point,且从0开始。一个字符串编码有责任编码一个code pointcode unit,且保持内部一致。

第一个2^16code pointUTF-16中被表示为单一的16位code unit。这被称之为Basic Multilingual Plane (BMP)。超出该范围的被认为是在一个辅助平面,code point已不能仅仅用16位来表示了。UTF-16通过引入surrogate pairs(代理对)来解决这个问题,一个code point可以由两个16位的code unit来表示。这意味着字符串中的任何单个字符可以由一个code unit或两个来表示。

ES5中所有的操作都是基于16位的code unit,这意味着你在处理包含代理对的字符串时会出现意想不到的结果。例如:

1
2
3
4
5
6
7
8
var text = "𠮷";

console.log(text.length); // 2
console.log(/^.$/.test(text)); // false
console.log(text.charAt(0)); // ""
console.log(text.charAt(1)); // ""
console.log(text.charCodeAt(0)); // 55362
console.log(text.charCodeAt(1)); // 57271

在这个例子中,单个Unicode字符是使用代理对来表示的,JavaScript字符操作会认为字符串由两个16位的字符组成。这意味着length为2,通过正则表达式匹配单个字符也失败了,charAt()也无法读取字符。charCodeAt()方法为每个code unit返回了正确的16为数字。

ES6中强制使用UTF-16来编码字符串。

codePointAt()

codePointAt()接受code unit的位置,并返回一个整数:

1
2
3
4
5
6
7
8
9
var text = "𠮷a";

console.log(text.charCodeAt(0)); // 55362
console.log(text.charCodeAt(1)); // 57271
console.log(text.charCodeAt(2)); // 97

console.log(text.codePointAt(0)); // 134071
console.log(text.codePointAt(1)); // 57271
console.log(text.codePointAt(2)); // 97

当字符为BMP范围内的字符时,codePointAt()charCodeAt()的行为是一样的,在非BMP字符时,charCodeAt()仅仅返回了位置0code unit,但是codePointAt()返回了整个code point,即使横跨多个code unit。对于位置1和位置2的,它俩返回值是相同的。

用以下方法可以判断是否为16位,还是32位:

1
2
3
4
5
6
function is32Bit(c) {
return c.codePointAt(0) > 0xFFFF;
}

console.log(is32Bit("𠮷")); // true
console.log(is32Bit("a")); // false

String.fromCodePoint()

String.fromCodePoint()就是和codePointAt()做相反的操作了。例如:

1
console.log(String.fromCodePoint(134071));  // "𠮷"

编码非BMP字符

ES5中允许字符包含用编码序列代表的16位Unicode字符。编码序列是通过\u加上4个16进制值,例如\u0061代表字符a

1
console.log("\u0061");      // "a"

但是当你用编码序列来代表大于FFFF的字符时,你会得到意想不到的结果:

1
console.log("\u20BB7");

因为Unicode编码序列总是包含4个16进制字符,ECMAScript计算\u20BB7为两个字符:\u20BB7。第一个字符为非打印的,第二个为数字7。

ES6通过引入扩展的Unicode编码序列解决了这个问题,将16进制数字包含在花括号内。这使得任何数量的十六进制字符可以指定为单个字符:

1
console.log("\u{20BB7}");     // "𠮷"

通过下面的函数可以判断是否支持这种写法:

1
2
3
4
5
6
7
8
function supportsExtendedEscape() {
try {
eval("'\\u{00FF1}'");
return true;
} catch (ex) {
return false;
}
}

正则表达式u修饰符

正则表达式也是基于16位的code unit来代表单个字符,这就对于𠮷/^.$/的正则表达式中不能匹配,ES6为正则表达式定义了一个新的修饰符,u也即Unicode。当一个正则表达式设置了u修饰符时,它将切换模式为工作在字符串,而不是code unit。这意味着正则表达式在包含代理对的字符串中不会迷惑。例如:

1
2
3
4
5
var text = "𠮷";

console.log(text.length); // 2
console.log(/^.$/.test(text)); // false
console.log(/^.$/u.test(text)); // true

在添加了u修饰符的正则表达式能以字符的方式来匹配字符串,而不是code unit

新增的String方法

includes()

如果给定字符在字符串的任何位置被找到,则返回true,否则返回false。例如:

1
2
3
var msg = "Hello world!";

console.log(msg.includes("ello"));

startsWith()

如果字符串以给定字符开始,则返回true,否则返回false。例如:

1
2
3
var msg = "Hello world!";

console.log(msg.startsWith("Hello"));

endsWith()

如果字符串以给定字符结束,则返回true,否则返回false。例如:

1
2
3
var msg = "Hello world!";

console.log(msg.endsWith("world!"));

repeat()

该方法接受一个数字作为参数,表示将原字符串重复的次数。例如:

1
2
var str = "cookfront";
console.log(str.repeat(3));

正则表达式修饰符y

ES6引入了新的正则表达式修饰符y,也即粘连,它与g修饰符比较类似,但是不同之处在于,g修饰符只确保剩余位置中存在匹配,而y修饰符确保匹配必须从剩余的第一个位置开始,这也就是粘连的涵义。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var text = "hello1 hello2 hello3",
pattern = /hello\d\s?/,
result = pattern.exec(text),
globalPattern = /hello\d\s?/g,
globalResult = globalPattern.exec(text),
stickyPattern = /hello\d\s?/y,
stickyResult = stickyPattern.exec(text);

console.log(result[0]); // "hello1 "
console.log(globalResult[0]); // "hello1 "
console.log(stickyResult[0]); // "hello1 "

pattern.lastIndex = 1;
globalPattern.lastIndex = 1;
stickyPattern.lastIndex = 1;

result = pattern.exec(text);
globalResult = globalPattern.exec(text);
stickyResult = stickyPattern.exec(text);

console.log(result[0]); // "hello1 "
console.log(globalResult[0]); // "hello2 "
console.log(stickyResult[0]); // Error! stickyResult is null

在上面的例子中,使用了三个正则表达式,一个使用了y修饰符,一个使用了g修饰符,一个没有使用修饰符。第一次匹配时我们可以看到结果都为hello1,匹配后我们将lastIndex置为1,即从第二个字符开始匹配,我们可以看到第二次匹配的结果没有修饰符的还是匹配hello1g修饰符的匹配hello2y修饰符在从第二个字符开始没有匹配任何东西所以返回null。我们也可以看出了y修饰符号隐含了头部匹配的标志^

文章目錄
  1. 1. 更好的Unicode支持
    1. 1.1. codePointAt()
    2. 1.2. String.fromCodePoint()
    3. 1.3. 编码非BMP字符
    4. 1.4. 正则表达式u修饰符
  2. 2. 新增的String方法
    1. 2.1. includes()
    2. 2.2. startsWith()
    3. 2.3. endsWith()
    4. 2.4. repeat()
  3. 3. 正则表达式修饰符y