ECMAScript6(4):字符串類型擴展

字符串擴展

//ES6
"\u{20BB7}"   //"𠮷"

"\uD842\uDFB7" === "\u{20BB7}";   //true
"\u01d1" === "\u004f\u030C";       //理論上是一致的, 但 js 返回了 false

//使用 normalize 統一編碼來解決這個問題
"\u01d1".normalize() === "\u004f\u030C".normalize();     //true

遺憾的是, normalize() 方法只能表示2個 utf-16 字符的合成, 要是3個或以上就只能本身用正則表達式解決了。javascript

至此, 一個字符有了6中表示方法:java

//如下結果都是 true
"\x7A" === "z";
"\u{7A}" === "z";
"\u007A" === "z";
"\172" === "z";
"\z" === "z";

javascript內部用 utf-16 格式存儲字符, 這樣倉促的引入 utf-32 的碼點會引發許多錯誤, 因此 ES6 在 String.prototype 上添加了 CodePointAt() 方法替換 charCodeAt(), 用靜態方法 String.fromCodePoint() 替換了 String.fromCharCode(), 以解決因編碼差別致使的計算錯誤。正則表達式

可是, 咱們依然要注意到一下錯誤:數組

var a="𠮷a";

console.log(a.length);       //3
console.log(a.charAt(0));    //"\uD842"
console.log(a.split(''));    //["\uD842", "\uDFB7", a]

//這些顯然不是咱們想要的, 咱們須要替換使用
console.log(a.codePointLength());       //下面咱們能夠本身簡單寫一個 codePointLength() 方法
console.log(a.at(0));    //"𠮷", ES7 方法, babel中有
console.log(a.toArray());    //下面咱們能夠本身簡單寫一個 toArray() 方法

爲此, 遍歷字符串中的每一個字符, 請使用 for...ofbabel

var a="𠮷a";
for(let alpha of a){
  console.log(alpha);    //依次輸出: 𠮷, a
}

除此以外, ES6 還提供了一些其餘的簡單方法, 這裏簡單帶過:函數

//動態方法
s.includes(str, n);   //s從下標 n 的字符起是否包含 str 字符串, 返回 Boolean, n 默認爲 0
s.startsWith(str, n); //s從下標 n 的字符起是否以 str 開頭, 返回 Boolean, n 默認爲 0
s.endWith(str, n); //s的前 n 個字符是否以 str 結尾, 返回 Boolean, n 默認爲字符串長度
s.repeat(n);   //返回將 s 重複 n 次的新字符串, 若是 n 是小數, 會向下取整;若是 n 是 infinity 或小於等於-1 會報錯;若是 n 大於-1且小於等於零, 返回空字符串;若是 n 爲 NaN, 返回空字符串;其他傳輸參數遵循隱式類型轉換。
s.padStart(minLen, str);  //對於小於 minLen 長度的字符串, 在 s 前用 str 重複補充爲 len 長度, 返回該新字符串, 不然返回原字符串。str默認爲空格
s.padEnd(minLen, str);  //對於小於 minLen 長度的字符串, 在 s 後用 str 重複補充爲 len 長度, 返回該新字符串, 不然返回原字符串。str默認爲空格

自定義函數計算字符串長度和大小, 以及轉化爲數組:性能

//計算字符串長度, 方法1
String.prototype.codePointLength = function(){
  var result = this.match(/[\s\S]/gu);
  return result ? result.length : 0;
};
//計算字符串長度, 方法2
String.prototype.codePointLength2 = function(){
  return [...this].length;
};

//計算字符大小
String.prototype.size = function(){
  var size = 0;
  for(let alpha of this){
    if(alpha.codePointAt(0) > 0xFFFF){
      size+=4;
    } else {
      size+=2;
    }
  }
  return size;
};

var a="𠮷a";
console.log(a.codePointLength());    //2
console.log(a.codePointLength2());    //2
console.log(a.size());   //6

//字符串拆分爲數組,方法1
String.prototype.toArray = function(nil){
  if(nil === undefined){
    return Array.from(this);
  }
  if(nil.constructor === RegExp || nil.constructor === String){
    var reg = new RegExp(nil, "u");
    return this.split(reg);
  }
}
//字符串拆分爲數組,方法2
String.prototype.toArray2 = function(nil){
  if(nil === undefined){
    return [...this];
  }
  if(nil.constructor === RegExp || nil.constructor === String){
    var reg = new RegExp(nil, "u");
    return this.split(reg);
  }
}

var a="𠮷ds𠮷asaf𠮷saf";
console.log(a.toArray());   //["𠮷", "d", "s", "𠮷", "a", "s", "a", "f", "𠮷", "s", "a", "f"]
console.log(a.toArray('a'));   //["𠮷ds𠮷", "s", "f𠮷s", "f"]
console.log(a.toArray('𠮷'));   //["", "ds", "asaf", "saf"]
console.log(a.toArray2());   //["𠮷", "d", "s", "𠮷", "a", "s", "a", "f", "𠮷", "s", "a", "f"]
console.log(a.toArray2('a'));   //["𠮷ds𠮷", "s", "f𠮷s", "f"]
console.log(a.toArray2('𠮷'));   //["", "ds", "asaf", "saf"]

模板字符串

ES5 中, 咱們寫一個多行字符很不方便:this

//咱們這樣寫動態字符串
var multiStr = "I am " + name;    //假定 name 已定義
//這樣寫多行字符串
var multiStr = "first line\nsecond line\nthird line";
//在或者這樣
var tempArr = ["first line", "second line", "third line"];   //多用於生成動態字符串。此外《編寫高質量代碼:改善JavaScript程序的188個建議》中指出, 這個方法寫靜態字符串同樣比加號(+)性能更好
var multiStr = tempArr.join("\n");

在 ES6 中利用反引號( `...` )和EL表達式(${...}), 咱們能夠這樣:編碼

//咱們這樣寫動態字符串
var multiStr = `I am ${name}`;    //假定 name 已定義
//這樣寫多行字符串
var multiStr = `
first line
second line
third line
`;

注意: 反引號中的全部空格和縮進都會被保留下來prototype

EL表達式中能夠放入任何表達式進行運算:

var x=2, y=3;
console.log(`x+y=${x+y}`);    //x+y=5

function plus(a, b){
  return a+b;
}
console.log(`x+y=${plus(x, y)}`);    //x+y=5

引用模板字符串自己:

//方法1
let str = 'return ' + '`Hello ${name}`';
let fun = new Function('name', str);
fun('Jack');

//方法2
let str2 = '(name) => `Hello ${name}`';
let fun2 = eval(str2);
fun2('Jack');

標籤模板

標籤模板是用來處理字符串的函數, 可是調用方式和以往大不相同, 是直接將模板字符串跟在函數名後面, 該函數的結構以下:

function funName(strings, ...values){
   //...
}

其中, 以EL表達式做爲分界, 先後和表達式之間的字符串部分, 會從左到右依次放入 strings 參數中;每個 EL 表達式會從左到右依次放入 values 參數中:

function tag(strings, ...values){
  console.log(strings[0]);
  console.log(strings[1]);
  console.log(strings[2]);
  console.log(values[0]);
  console.log(values[1]);
  return 'OK';
}
//固然, 也能夠這樣寫(關於展開運算符, 這裏不作深刻討論, 具體在 ES6 的函數部分展開)
function tag(strings, value0, value1){
  console.log(strings[0]);
  console.log(strings[1]);
  console.log(strings[2]);
  console.log(value0);
  console.log(value1);
  return 'OK';
}

下面是完整的調用:

var a = 5;
var b = 10;

function tag(strings, ...values){
  console.log(strings[0]);      //"Hello "
  console.log(strings[1]);      //" world "
  console.log(strings[2]);      //"!"
  console.log(values[0]);       //15
  console.log(values[1]);       //50
  return 'OK';
}

console.log(tag`Hello ${a+b} world ${a*b}!`);     //"OK"

固然, 標籤模板的正經用法以下:

var a = 5;
var b = 10;

function tag(strings, ...values){
  var result = [], i = 0;
  while(i < strings.length){
    result.push(strings[i]);
    if(values[i]){
      result.push(values[i]);
    }
    i++;
  }
  return result.join('');
}

console.log(tag`Hello ${ a + b } world ${ a * b}!`);   //Hello 15 world 50!

固然, 若是將上方 tag 函數中的 <, >, & 都替換掉, 並忽略 values 中的內容, 能夠用來過濾用戶輸入數據, 防止惡意代碼注入。

值得一提的是, tag的第一個參數 strings 還有一個 raw 屬性, 也是一個數組, 內容分別對應 strings 數組的值的原生字符。好比 strings 中 strings[0]=「a\nb", 則 strings.raw[0]="a\\nb"。除此以外, ES6 還添加了 String.raw() 方法, 用於解析模板字符串, 但返回值的字符串是原生字符, 其內部基本以下:

String.raw = function(strings, ...values){
  var output = "";
  for(var index = 0; index < values.length; index++){
    output += strings.raw[index] + value[index];
  }
  output += string.raw[index];
  retrun output;
};
相關文章
相關標籤/搜索