實例方法
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}!`