一、字符串拓展
(1)字符表示
-
UTF-16编码回顾 在JS里面的字符是以utf-16编码方式进行解析 utf-16的编码范围:
- U+0000 ~ U+D800:两个字节表示一个字符
- U+D800 ~ U+FFFF:属于空位,四个字节表示一个字符(超出编码极限的字符会以这种方式解析)
超出编码极限的字符也可用花括号包裹,JS会帮忙解析,例如:\u{2pbb7} == 𠮷
-
字符的表示方式
-
代码补全 如果码点不足4位,则用0补全 console.log('\u0041\u0042\u0043');
-
{}解析 可以解析超出编码极限,或者没有补全的码点 console.log('\u{0041}\u{0042}\u{0043}');
console.log('\u{41}\u{42}\u{43}');
console.log('\u{2pbb7}');
console.log('\uD842\uDFB7' === '\u{20BB7}');
(2)码点相关方法
-
length 码点长度就是字符长度 var s = "\u{20BB7}";
console.log(s.length);
这样的处理方式不符合预期,只对应了一个字符,长度应该是1,而不是2
-
charAt(es5) 输出索引所对应的字符 缺点:不能正确处理超出编码极限的字符 console.log(s.charAt(0));
console.log(s.charAt(1));
-
charCodeAt (es5) 输出索引所对应的码点(10进制) 缺点:不能正确处理超出编码极限的字符 console.log(s.charCodeAt(0));
console.log(s.charCodeAt(0));
console.log(Number.prototype.toString.call(55362,16));
console.log(Number.prototype.toString.call(57271,16));
-
codePointAt(es6) 输出索引所对应的码点(10进制) 能正确处理超出编码极限的字符,并能拿到索引对应的码点 var s= "𠮷a"
console.log(s.codePointAt(0));
console.log(Number.prototype.toString.call(55362,16));
console.log(s.length);
console.log(s.codePointAt(0));
console.log(s.codePointAt(1));
console.log(s.codePointAt(2));
console.log(Number.prototype.toString.call(97,16));
console.log('\u0061');
console.log('\u{61}');
应用:判断一个字符是2个字节还是4个字节组成 function is32Bit(c){
return c.codePointAt(0) > 0xffff;
}
console.log(is32Bit('吉'));
console.log(0xffff);
-
迭代器 可以正确的输出超出编码极限的字符 var s = "𠮷a";
for (let i = 0; i < str.length; i++) {
console.log(str[i]);
}
for (let value of s) {
console.log(value);
}
-
fromCharCode(es5) 传入一个码点返回一个对应的字符 缺点:不能识别超出编码极限的码点 console.log(String.fromCharCode(0x20bb7));
console.log(String.fromCharCode(0x20bb7) === String.fromCharCode(0x0bb7));
-
fromCodePoint(es6) 传入一个码点返回一个对应的字符 能识别超出编码极限的码点 String.fromCodePoint(0x20BB7);
(3)字符串新增方法
-
includes / startsWith / endsWith 判读一个字符串是否在另一个字符串当中、开头、结尾 let s = "Hello world!";
console.log(s.includes("o"));
console.log(s.startsWith('Hello'));
console.log(s.endsWith('!'));
-
repeat 把原本的字符串重复N次 console.log('x'.repeat(3));
console.log('x'.repeat(2.9));
console.log('x'.repeat(NaN));
console.log('x'.repeat(0));
console.log('x'.repeat("3"));
-
padStart / padEnd 开头、结尾填充 指定字符串 至 指定长度 console.log('x'.padStart(5,"ab"));
console.log('x'.padStart(4,"ab"));
console.log('x'.padEnd(4,"ab"));
console.log('x'.padEnd(5,"ab"));
二、模板字符串
(1)基本用法
let name = 'web'
let info = 'developer'
let m = `I am a ${name} ${info}`;
console.log(m);
(2)进阶用法
模板里面是表达式,可以做很多事情:
-
可以运算 let x = 1;
let y = 2;
console.log(`${x} + ${y} = ${x+y}`)
-
可以调用对象 let obj = {x:1,y:2};
console.log(`${obj.x + obj.y}`)
-
可以调用函数 function fn(){
return [1,2,3,4];
}
console.log(`foo ${fn()} bar`)
模板里会隐式转换成字符串
-
可以嵌套字符串 let msg = `Hello, ${'place'}`;
console.log(msg);
(3)模板渲染方法
const temp = arr1 => `
<table>
${
arr1.map(addr => `
<tr><td>${addr.first}</td></tr>
<tr><td>${addr.last}</td></tr>
`)
}
</table>
`
const data = [
{first:"zhang",last:"san"},
{first:"li",last:"si"},
]
console.log(temp(data));
输出:
发现有个逗号,这是因为map返回的是一个数组,而模板内部会隐式转换成字符串,所以导致了这个结果
解决方法:
${
arr1.map(addr => `
<tr><td>${addr.first}</td></tr>
<tr><td>${addr.last}</td></tr>
`).join('')
}
用join方法把数组拼接起来就好了
(4)注入问题
一些恶意的模板数据会通过这种方式渲染到页面
const data = [
{first:"zhang",last:"<script>alert('abc')</script>"},
{first:"li",last:"si"},
]
(5)标签模板
专门用于解决恶意注入的问题
通过标签模板 tag`` 的形式调用函数,可以在函数内部做相应的处理
参数依次是:以{}分隔的字符串,往后{}里的值
let a = 5;
let b = 10;
tag `Hello ${a+b} world${a*b}`;
function tag($,$1,$2){
console.log($,$1,$2)
}
解决方案:
function SaferHTML(tempData) {
let s = '';
for (let i = 1; i < arguments.length; i++) {
let arg = String(arguments[i]);
s += arg.replace(/</g, "<").replace(/>/g, ">")
}
return s;
}
let sender = '<script>alert("abc")<\/script>'
let message = SaferHTML `<p>${sender} has set you message</p>`
console.log(message);
输出:
注意区分:字符串里的实体符是不会被浏览器解析的,标签里的实体符才会被解析
|