实例方法
codePointAt()
用途:返回字符码点的十进制值
js内部,字符以UTF-16的格式存储,每个字符固定为2个字节。
对那些需要4个字节存储的字符(Unicode码点大于0xFFFF的字符),js会认为它们是2个字符。
let str='一';
console.log(str.codePointAt(0)); //19968 十进制code point
console.log(str.codePointAt(0).toString(16)); //4e00 十六进制code point
let str1='𠮷a';
console.log(str1.codePointAt(0)); //134071 十进制code point
console.log(str1.codePointAt(0).toString(16)); //20bb7 十六进制code point
console.log(str1.codePointAt(1)); //57271 十进制code point
console.log(str1.codePointAt(1).toString(16)); //dfb7 十六进制code point
console.log(str1.codePointAt(2)); //97 十进制code point
console.log(str1.codePointAt(2).toString(16)); //61 十六进制code point
js将“𠮷a”视为三个字符,codePointAt方法在第一个字符上,正确地识别了“𠮷”,返回了它的十进制码点134071(即十六进制的20BB7)。在第二个字符(即“𠮷”的后两个字节)和第三个字符“a”上,codePointAt方法的结果与charCodeAt方法相同。
注意到codePointAt方法的参数,仍然是不正确的。比如,上面代码中,字符a在字符串的正确位置序号应该是1,但是必须向codePointAt方法传入2。
var s='𠮷a';
s.codePointAt(0).toString(16)// "20bb7"
s.codePointAt(2).toString(16)// "61"
解决办法是:使用for...of循环,因为它会正确识别32位的UTF-16字符。
var s='𠮷a';
for(let ch of s){
console.log( ch.codePointAt(0).toString(16) );
}
// 20bb7
// 61
codePointAt方法是测试一个字符由两个字节还是由四个字节组成的最简单方法
function is32Bit(c){
return c.codePointAt(0)>0xFFFF;
}
is32Bit("𠮷") // true
is32Bit("a") // false
includes()
用途:判断一个字符串是否包含参数字符串
返回值:布尔值
console.log('hello world'.includes('hello')) //true
startsWith()
用途:判断一个字符串是否以参数字符串开头
返回值:布尔值
console.log('hello world'.startsWith('hello')) //true
endsWith()
用途:判断一个字符串是否以参数字符串结尾
返回值:布尔值
console.log('hello world'.endsWith('hello')) //false
console.log('hello world'.endsWith('world')) //true
repeat()
用途:将原字符串重复n次
返回值:不改变原字符串,返回一个新字符串
let hab= 'hello';
console.log(hab); // hello
console.log(hab.repeat(3)); // hellohellohello
padStart()
用途:某字符串不够指定长度,会在头部补全
返回值:不改变原字符串,返回一个新字符串
let ccc = 'x';
let cc = ccc.padStart(5,'ab');
console.log(ccc);
// x
console.log(cc);
// ababx
padEnd()
用途:某字符串不够指定长度,会在尾部补全
返回值:不改变原字符串,返回一个新字符串
let ccc = 'x';
let cc = ccc.padEnd(5,'ab');
console.log(ccc);
// x
console.log(cc);
// xabab
静态方法
String.fromCodePoint()
用途:该方法可接受一个或多个指定的 Unicode 值,然后返回一个字符串。
ES5提供String.fromCharCode方法,用于从码点返回对应字符,但是这个方法不能识别32位的UTF-16字符(Unicode编号大于0xFFFF)。
String 对象实例中的有方法charCodeAt(),可返回指定位置的字符的 Unicode 编码
String 对象静态方法fromCharCode(),可根据Unicode码返回字符串
let str2 = String.fromCharCode(0x20BB7)
console.log(str2);
// ஷ
let str3 = String.fromCharCode(0x0BB7)
console.log(str3);
// ஷ
上面代码中,String.fromCharCode不能识别大于0xFFFF的码点,所以0x20BB7就发生了溢出,最高位2被舍弃了,最后返回码点U+0BB7对应的字符,而不是码点U+20BB7对应的字符。
ES6提供了String.fromCodePoint方法,可以识别大于0xFFFF的字符,弥补了String.fromCharCode方法的不足。在作用上,正好与codePointAt方法相反。
- 前面加0x,表示16进制的数值
- 字符串中使用‘\u’进行转码,将后面的16进制数据变成可识别的汉字
console.log( String.fromCodePoint(0x20BB7) )
// "𠮷"
console.log( String.fromCodePoint(0x78,0x1f680,0x79)==='x\uD83D\uDE80y' );
// true
console.log( String.fromCodePoint(0x78,0x1f680,0x79) )
// x🚀y
上面代码中,如果String.fromCodePoint方法有多个参数,则它们会被合并成一个字符串返回。
注意,fromCodePoint方法定义在String对象上,而codePointAt方法定义在字符串的实例对象上。
字符串的遍历器接口
ES6为字符串添加了遍历器接口,使得字符串可以被for...of循环遍历。
for(let codePoint of 'foo'){
console.log(codePoint)
}
// "f"// "o"// "o"
此遍历器最大的优点是可识别大于0xFFFF的码点,传统的for循环无法识别这样的码点。
var text=String.fromCodePoint(0x20BB7);
for(let i=0;i<text.length;i++){
console.log(text[i])
}
// �
// �
for(let ii of text){
console.log(ii)
}
// 𠮷
上面代码中,字符串text只有一个字符,但是for循环会认为它包含两个字符(都不可打印),而for...of循环会正确识别出这一个字符。
模板字符串
// 传统js输出模板
$('#result').append(
'There are <b>'+basket.count+'</b>'+
'items in your basket, '+
'<em>'+basket.onSale+
'</em> are on sale!');
// ES6引入模板字符串来解决上面写法的繁琐以及不方便
$('#result').append(`
There are <b>${basket.count}</b> items
in your basket,<em>${basket.onSale}</em>
are on sale!
`);
模板字符串(template string)是增强版字符串String,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量 or 函数等。
// 普通字符串
let str4 = `In JS '\n' is a line-feed`;
console.log('str4 = '+str4);
// str4 = In JS '
// ' is a line-feed
// 多行字符串
let str5 = `In JS this is
not legal`;
console.log('str5 = '+str5);
// str5 = In JS this is
// not legal
// 字符串中嵌入变量
var name = "dengjing",time = "today";
console.log(`Hello ${name},happy ${time}!`);
// Hello dengjing,happy today!
// 如在模板字符串中要使用反引号,则在其前面要用反斜杆转义。
var greeting = `\`Yo\` World!`;
console.log('greeting = '+greeting);
// greeting = `Yo` World!
// 使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出中。
console.log(`
<ul>
<li>first</li>
<li>second</li>
</ul>
`);
//
// <ul>
// <li>first</li>
// <li>second</li>
// </ul>
// 大括号内可放入任意的js表达式,可进行运算,以及引用对象属性
var x = 1;
var y = 2;
console.log(`${x} + ${y} = ${x+y}`);
// 1 + 2 = 3
console.log(`${x} + ${y*2} = ${x+y*2}`);
// 1 + 4 = 5
var obj = {x:1,y:2};
console.log(`${obj.x+obj.y}`);
// 3
// 模板字符串中调用函数
function fnc(){
return "Hello World";
}
console.log(`foo ${fnc()} bar`);
// foo Hello World bar
attention: 如${}中运行后的值,不是String类型,将按照一般的规则转化为字符串。例如:${}中是一个对象,将默认调用对象的toString()方法。
模板字符串中甚至还能嵌套
// 模板字符串中甚至还能嵌套
const tmpl = addrs => `
<table>
${addrs.map(addr=>`
<tr><td>${addr.first}</tr></td>
<tr><td>${addr.last}</tr></td>
`).join('')}
</table>
`;
const data = [
{ first:'<Jane>',last:'Bond' },
{ first:'Lars',last:'<Croft>' },
];
console.log( tmpl(data) );
//
// <table>
//
// <tr><td><Jane></tr></td>
// <tr><td>Bond</tr></td>
//
// <tr><td>Lars</tr></td>
// <tr><td><Croft></tr></td>
//
// </table>
引用模板字符串本身的写法,如下:
// 方法一
let returnStr = 'return ' + '`Hello ${name}!`';
let func1 = new Function('name',returnStr);
console.log(func1);
// ƒ anonymous(name
// ) {
// return `Hello ${name}!`
// }
console.log( func1('Jing') );
// Hello Jing!
// 方法二
let fnStr = ' (name)=>`Hello ${name}!` ';
// let func2 = eval.call(null,fnStr);
let func2 = eval(fnStr);
console.log(func2);
// (name)=>`Hello ${name}!`
console.log( func2('Deng') );
// Hello Deng!
标签模板
模板字符串,它还可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。
这被称为“标签模板”功能(tagged template)。
alert`9999999`;
// 相当于alert(9999999);
“标签模板”,其实不是模板,而是函数调用的一种特殊形式。
“标签”指的就是函数,而“模板字符串”就是它的参数。
“标签模板”中,如果模板字符串中有变量,就不再是简单调用了,而是要将模板字符串先处理成多个参数,在调用函数。
let a = 1;
let b = 9;
console.log`Hello ${ a + b } world ${ a * b }`
// (3) ["Hello ", " world ", "", raw: Array(3)] 10 9
// alert`Hello ${ a + b } world ${ a * b }`
// Hello , world ,
var x = 5;
var y = 10;
tag`Hello ${x+y} world ${x*y}`;
function tag(){
console.log(arguments);
// Arguments(3)
// 0: (3) ["Hello ", " world ", "", raw: Array(3)]
// 1: 15
// 2: 50
}
// function tag(stringArr,value1,value2){
// // ...
// }
// 等同于
// function tag(stringArr,...values){
// // ...
// }
上面代码,整个表达式的返回值就是tag函数处理模板字符串后的返回值。
函数tag会依次接收到多个参数。
tag函数的第一个参数是一个数组,该数组的成员是模板字符串中那些没有变量替换的部分,也就是说,变量替换只发生在数组的第一个成员与第二个成员之间、第二个成员与第三个成员之间,以此类推。
tag函数的其他参数都是模板字符串各个变量被替换后的值。
tag函数所有参数的实际值如下:
第一个参数:["Hello ", " world ", ""]
第二个参数:15
第三个参数:50
也就是说,tag函数实际的调用形式为:tag(["Hello ", " world ", ""],15,50)
var total = 30;
var msg = passthru`The total is ${total} (${total*1.05} with
tax)`
function passthru(literals) {
var result = '';
var i = 0;
while (i < literals . length) {
result+= literals[i++] ;
if (i < arguments . length) {
result+= arguments[i] ;
}
}
return result;
}
console.log(msg);
// The total is 30 (31.5 with
// tax)
passthru函数采用rest参数的写法如下:
function passthru(literals,...values) {
var output = '';
for (var index = 0;index<values.length;index++){
output += literals[index]+values[index];
}
output += literals[index];
return output;
}
“标签模板”的一个重要应用就是过滤HTML字符串,防止用户输入恶意内容。
function SaferHTML(templateData){
var s = templateData[0];
for (var i = 1; i < arguments.length; i++){
var arg = String(arguments[i]);
// Escape special characters in the substitution .
s += arg.replace(/&/g,"&")
.replace(/</g,"<")
.replace(/>/g,">");
// Don't escape special characters the template.
s += templateData[i];
}
return s;
}
var sender = " <script> alert('abc') "; // 恶意代码
var message =
SaferHTML`<p>${sender} has sent u a message.</p>`;
console.log(message);
// <p> <script> alert('abc') has sent u a message.</p>
标签模板的另一个应用是多语言转换(国际化处理)
i18n`Welcome to ${siteName},you are visitor number ${visitorNumber}!`