es6学习笔记-字符串的扩展_v1.0
字符的Unicode表示法
JavaScript 允许使用uxxxx的形式表示一个字符,但在 ES6 之前,单个码点仅支持u0000到uFFFF,超出该范围的必须用双字节形式表示,否则会解析错误。ES6对这一点做出了改进,只要将码点放入大括号,就能正确解读该字符,不受限于4位。例如下面的写法就是合法的,能够被正确解析:
//在es6后才可以,在es5的时候不行
"\u{20BB7}" // "?"
codePointAt()
JavaScript内部,字符以UTF-16的格式储存,每个字符固定为2个字节。
对于那些需要4个字节储存的字符(Unicode码点大于0xFFFF的字符),JavaScript会认为它们是两个字符。
codePointAt方法,能够正确处理4个字节储存的字符,返回一个字符的码点。
codePointAt方法会正确返回32位的UTF-16字符的码点。
注意例子是?,汉字“?”(注意,这个字不是”吉祥“的”吉“)的码点是0x20BB7,UTF-16编码为0xD842 0xDFB7(十进制为55362 57271),需要4个字节储存。
var s = '?a';
console.log(s.length); //3,?使用了2个字节来存储,a使用了一个字节存储
console.log(s.codePointAt(0)); // 134071
console.log(s.codePointAt(1)); // 57271
console.log(s.codePointAt(2)); // 97
codePointAt方法是测试一个字符由两个字节还是由四个字节组成的最简单方法。
function is32Bit(c) {
//超过2个字节组成的字符串的第一位码点都是大于0xFFFF
return c.codePointAt(0) > 0xFFFF;
}
console.log(is32Bit("?")) // true
console.log(is32Bit("a")) // false
ES6 提供了 codePointAt(),能够正确处理4个字节存储的字符,返回一个字符的码点。
但需要注意的是,这并没有改变 JavaScript 将2个字节视为1个字符的事实,只是自动识别出了这是个4字节的字符并返回了正确的码点而已
对于单个4字节的字符(例如'?')来说,charPointAt(0)返回完整字符的十进制码点,charPointAt(1)返回这个字符的后2个字节的十进制码点,效果等同于charCodeAt(1)。
参考
var s = '?a';
for (let ch of s) { //遍历s字符串,会有2个字符串被遍历,因为他的长度是2
console.log(ch.codePointAt(0));
}
// 134071,能知道这是一个超过四位(2个字节)的字符串(?)
// 97,这是一个只需要2位(1个字节)的字符串(a)
-
编码格式的检测:
专家给每种格式和字节序规定了一些特殊的编码,这些编码在unicode 中是没有使用的,所以不用担心会冲突。这个叫做BOM(Byte Order Mark)头。意思是字节序标志头。通过它基本能确定编码格式和字节序。
UTF编码 ║ Byte Order Mark UTF-8 ║ EF BB BF UTF-16LE ║ FF FE UTF-16BE ║ FE FF UTF-32LE ║ FF FE 00 00 UTF-32BE ║ 00 00 FE FF
所以通过检测文件前面的BOM头,基本能确定编码格式和字节序。但是这个BOM头只是建议添加,不是强制的,所以不少软件和系统没有添加这个BOM头(所以有些软件格式中有带BOM头和NoBOM头的选择)
UTF-16长度相对固定,只要不处理大于U200000范围的字符,每个Unicode代码点使用16位即2字节表示,超出部分使用两个UTF-16即4字节表示。按照高低位字节顺序,又分为UTF-16BE/UTF-16LE。参考
String.fromCodePoint()
String.fromCodePoint()
就是和codePointAt()
做相反的操作了。例如:
console.log(String.fromCodePoint(134071)); // "?"
字符串的遍历器接口
这个遍历器最大的优点是可以识别大于0xFFFF的码点
for (let codePoint of 'foo') {
console.log(codePoint)
}
// "f"
// "o"
// "o"
//能识别大于0xFFFF的码点
var text = String.fromCodePoint(0x20BB7);
//用for不行
for (let i = 0; i < text.length; i++) {
console.log(text[i]);
}
// " "
// " "
//用遍历器可以
for (let i of text) {
console.log(i);
}
// "?"
includes(), startsWith(), endsWith()
传统上,JavaScript只有indexOf方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6又提供了三种新方法。
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。
var s = 'Hello world!';
//第二个参数代表开始位置
console.log(s.startsWith('world', 6))// true
console.log(s.endsWith('Hello', 5)) // true
console.log(s.includes('Hello', 6)) // false
repeat()
repeat方法返回一个新字符串,表示将原字符串重复n次。
console.log('x'.repeat(3)) // "xxx"
console.log('na'.repeat(0)) // ""
console.log('na'.repeat(2.9)) // "nana"
'na'.repeat(Infinity)// RangeError
'na'.repeat(-1)// RangeError
padStart(),padEnd()
ES2017(es6是es2016) 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全。
padStart和padEnd一共接受两个参数,第一个参数用来指定字符串的最小长度,第二个参数是用来补全的字符串。
//主要用于补全
console.log('1'.padStart(10, '0')); // "0000000001"
console.log('12'.padStart(10, '0'))// "0000000012"
console.log('123456'.padStart(10, '0')) // "0000123456"
node 6.95还不支持,现在是用babel-node来测试的
模板字符串
使用反引号,反引号代替以前的单引号或者双引号
使用大括号支持任意的JavaScript表达式,可以进行运算,以及引用对象属性和函数
// 普通字符串
`In JavaScript '\n' is a line-feed.`
// 多行字符串
`In JavaScript this is
not legal.`
console.log(`string text line 1
string text line 2`);
// 字符串中嵌入变量
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
//如果在模板字符串中需要使用反引号,则前面要用反斜杠转义。
var greeting = `\`Yo\` World!`;
//使用大括号的情况
var x = 1;
var y = 2;
`${x} + ${y} = ${x + y}`
// "1 + 2 = 3"
`${x} + ${y * 2} = ${x + y * 2}`
// "1 + 4 = 5"
var obj = {x: 1, y: 2};
`${obj.x + obj.y}`
// 3
//模板字符串之中还能调用函数,要用大括号
function fn() {
return "Hello World";
}
`foo ${fn()} bar`
// foo Hello World bar
传统写法vs新写法
//传统写法
$('#result').append(
'There are <b>' + basket.count + '</b> ' + //不断用+号连接
'items in your basket, ' +
'<em>' + basket.onSale +
'</em> are on sale!'
);
//新写法
$('#result').append(` //一个反引号括起来,然后直接写,用大括号包括变量
There are <b>${basket.count}</b> items
in your basket, <em>${basket.onSale}</em>
are on sale!
`);
//模板字符串中嵌入变量,需要将变量名写在${}之中。
function authorize(user, action) {
if (!user.hasPrivilege(action)) {
throw new Error(
// 传统写法为
// 'User '
// + user.name
// + ' is not authorized to do '
// + action
// + '.'
//新写法
`User ${user.name} is not authorized to do ${action}.`);
}
}
模板嵌套
map() 方法创建一个新数组,其结果是该数组中的每个元素调用一个提供的函数。
const tmpl = addrs => ` //箭头后面跟的是反引号
<table>
${addrs.map(addr => ` //不断解析,直到获取到data数组的元素里面的对象属性
<tr><td>${addr.first}</td></tr>
<tr><td>${addr.last}</td></tr>
`).join('')}//将他们直接连接起来
</table>
`;
//初始化需要处理的模板
const data = [
{ first: '<Jane>', last: 'Bond' },
{ first: 'Lars', last: '<Croft>' },
];
console.log(tmpl(data));
//返回结果
// <table>
//
// <tr><td><Jane></td></tr>
// <tr><td>Bond</td></tr>
//
// <tr><td>Lars</td></tr>
// <tr><td><Croft></td></tr>
//
// </table>
如果需要引用模板字符串本身,在需要时执行,可以像下面这样写。
// 写法一
let str = 'return ' + '`Hello ${name}!`';//将模板本身保存起来为变量
let func = new Function('name', str); //作为functionBody使用
func('Jack') // "Hello Jack!"
// 写法二
let str = '(name) => `Hello ${name}!`';
let func = eval.call(null, str); //不建议使用eval
func('Jack') // "Hello Jack!"
new Function ([arg1[, arg2[, ...argN]],] functionBody)
参数arg1, arg2, ... argN:被函数使用的参数的名称必须是合法命名的。
functionBody:一个含有包括函数定义的JavaScript语句的字符串。
参考引用:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。