ES6:字符串擴展

實例方法

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,"&amp;")
                .replace(/</g,"&lt;")
                .replace(/>/g,"&gt;");
        // 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> &lt;script&gt; alert('abc')  has sent u a message.</p>

標籤模板的另一個應用是多語言轉換(國際化處理)

i18n`Welcome to ${siteName},you are visitor number ${visitorNumber}!`

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章