ECMAScript 6的一些注意點 第二部分(字符串拓展 -- 數值拓展)

標籤模板

  • “標籤”指的就是函數,緊跟在後面的模板字符串就是它的參數。
  • 如果模板字符裏面有變量,會將模板字符串先處理成多個參數,再調用函數。
  • 函數的第一個參數是一個數組,該數組的成員是模板字符串中那些沒有變量替換的部分。

假設有以下函數:

let a = 1;
let b = 2;
function tag(x,y){
    return x,y;
}
tag`this is ${a} and ${a+b}`;

注意,由於使用模板字符串形式,第一個參數會是一個只接收非變量的數組(存在一個raw屬性,用來保存轉以後的原字符串),所以這裏會輸出,可以看到輸出參數並不全,因爲非變量數組佔用了一個變量位置:

["this is" , " and " , "" ] 1
//x即爲存放非變量的數組,故y爲第二個參數1

相當於這麼調用的函數:

tag(["this is","and",""],1,3);

所以如果想取到全部的參數可以:

//1,對應相同數量的參數
function tag(x,y,z){
    return x,y,z    // y = 1 , z = 3
}
//2,使用reset參數
function tag(x , ...y){
    return x,y;    //x = ['this is' , 'and' , ""] y = [1,3]
}
//3,arugments
function tag(x){
    return arguments;    //0:['this is' , 'and' , ''] 1:1 2:3
}

 

按照調用的語句拼接:

function tag(x,...y){
    let output = '';
    y.forEach((item,index)=>{
       output += x[index] + item;
    })
    output += x[y.length];
    return output;    // this is 1 and 3
}

常見用法:防止用戶惡意插入代碼進行XSS攻擊,場景:(借鑑自https://blog.csdn.net/qq_43287488/article/details/82873336

1、攻擊者通過評論表單提交將<script>alert(‘aaa’)</script>提交到網站

2、網站後端對提交的評論數據不做任何操作,直接存儲到數據庫中

3、其他用戶訪問正常訪問網站,並且需要請求網站的評論數據

4、網站後端會從數據庫中取出數據,直接返回給用戶

5、用戶得到頁面後,直接運行攻擊者提交的代碼<script>alert(‘aaa’)</script>,所有用戶都會在網頁中彈出aaa的彈窗

應用:

function safeHTML(templateData,...reset){
    let s = templateData[0]; 
    reset.foreach((item,index)=>{
       let arg = String(item);
       s += arg.replace(/&/g,"&amp;")    //將&轉換爲字符串&amg
               .replace(/</g,"&lt;")     //將<轉換爲字符串&lt;
               .replace(/>/g,"&gt;");    //將>轉換爲&gt;
       s += templateData[index];            
    })
    return s;    //返回轉義後的字符串
}
let sender = '<script>alert("abc") < /script>'; // 用戶輸入的惡意代碼
let message = SaferHTML`<p>${sender} has sent you a message.</p>`;
// message -> <p>&lt;script&gt;alert("abc") &lt; /script&gt;<p>

標籤函數與模板編譯結合,參照官網例子:

// 下面的hashTemplate函數
// 是一個自定義的模板處理函數
let libraryHtml = hashTemplate`
  <ul>
    #for book in ${myBooks}
      <li><i>#{book.title}</i> by #{book.author}</li>
    #end
  </ul>
`;

按照自己想法處理了一下,主要原理參照模板編譯,正則替換爲JavaScript表達式進行解析:

   let myBooks = [{
        title: "ES6",
        author: "Javascript"
    }];
    let libraryHtml = hashTemplate `
  <ul>
    #for book of ${myBooks}
      <li><i>#{book.title}</i>  by  #{book.author}</li>
    #end
  </ul>
`;
function hashTemplate(template, ...reset) {
        let output = '';
        //正則表達式轉換
        let delbrackets = /<(.+?)>/g ,    //()中的內容
         delbraces = /#{(.+?)}/g ,        //{}中的內容
        changefor = /#for/g,              //#for的更改
         changeend = /#end/g;             //#end的替換
        template.forEach((element, index) => {
            //用三元判斷拼接的順序
            index > 0 ? output += element : output += element + 'myBooks){';
        });
        //使用replace進行替換,by字符串實屬無奈,學藝不精
        output = output
                .replace(delbrackets, 'echo(`<$1>`) \n')
                .replace(delbraces, '\n echo($1)\n')
                .replace(changefor, 'for(')
                .replace(changeend, '}')
                .replace(/(by)/g, ' echo(`$1`)  ');
        let script =
            `
           (function parse(myBooks){
                let html = '';
                function echo(str){
                    html+=str;
                }
                ${output}
                return html;
           })
        `
        let parse = eval(script);
        document.querySelector('div').innerHTML = parse(...reset);
}

該方法類似於模板編譯實例的解法,更改完輸出的字符串爲:

(function parse(myBooks) {
    let html = '';
    function echo(str) {
        html += str;
    }
    echo(`<ul>`)
    for (book of myBooks) {
        echo(`<li>`)
        echo(`<i>`)
        echo(book.title)
        echo(`</i>`)
        echo(`by`)
        echo(book.author)
        echo(`</li>`)
    }
    echo(`</ul>`)
    return html;
})

String.raw()

用來充當模板字符串的處理函數,返回一個斜槓都被轉義(即斜槓前面再加一個斜槓)的字符串。

String.raw`Hi\n${2+3}!`;
// 返回 "Hi\\n5!"

String.raw`Hi\u000A!`;
// 返回 "Hi\\u000A!"

正則的擴展(暫時跳過)


數值的擴展

新增方法:

  1. Number.isFinite() 用來檢查一個數值是否爲有限的(finite)
  2. Number.isNaN()用來檢查一個值是否爲NaN。
  3. 而這兩個新方法只對數值有效,Number.isFinite()對於非數值一律返回false, Number.isNaN()只有對於NaN才返回true,非NaN一律返回false。

  4. ES6 將全局方法parseInt()和parseFloat(),移植到Number對象上面,Number.parseInft(),Number.parseFloat()。

  5. Number.isInteger()用來判斷一個數值是否爲整數,如果數值的精度超過這個限度,第54位及後面的位就會被丟棄,這種情況下,Number.isInteger可能會誤判。

  6. 如果對數據精度的要求較高,不建議使用Number.isInteger()判斷一個數值是否爲整數。

  7. Number.EPSILON,JavaScript 能夠表示的最小精度,實質是一個可以接受的最小誤差範圍。

  8. Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER這兩個常量,用來表示這個範圍的上下限。

  9. Number.isSafeInteger()則是用來判斷一個整數是否落在這個範圍之內。


Math對象的拓展

ES6 在 Math 對象上新增了 17 個與數學相關的方法。所有這些方法都是靜態方法,只能在 Math 對象上調用。

  1. Math.trunc方法用於去除一個數的小數部分,返回整數部分,對於非數值,Math.trunc內部使用Number方法將其先轉爲數值,對於空值和無法截取整數的值,返回NaN。

  2. Math.sign方法用來判斷一個數到底是正數、負數、還是零。對於非數值,會先將其轉換爲數值,如果參數是非數值,會自動轉爲數值。對於那些無法轉爲數值的值,會返回NaN。

  3. 返回五種值:

    參數爲正數,返回+1;
    參數爲負數,返回-1;
    參數爲 0,返回0;
    參數爲-0,返回-0;
    其他值,返回NaN。

     

  4. Math.cbrt()方法用於計算一個數的立方根,對於非數值,先使用Number方法將其轉爲數值。

  5. Math.clz32()方法將參數轉爲 32 位無符號整數的形式,然後這個 32 位值裏面有多少個前導 0,對於空值或其他類型的值,Math.clz32方法會將它們先轉爲數值,然後再計算。

  6. Math.imul()方法返回兩個數以 32 位帶符號整數形式相乘的結果,返回的也是一個 32 位的帶符號整數。

  7. Math.fround()方法返回一個數的32位單精度浮點數形式,主要作用,是將64位雙精度浮點數轉爲32位單精度浮點數,對於 NaN 和 Infinity,此方法返回原值。對於其它類型的非數值,Math.fround 方法會先將其轉爲數值,再返回單精度浮點數。

  8. Math.hypot()方法返回所有參數的平方和的平方根,如果參數不是數值,Math.hypot方法會將其轉爲數值。只要有一個參數無法轉爲數值,就會返回 NaN。

對數方法

  • Math.expm1(x)返回 ex - 1,即Math.exp(x) - 1
  • Math.log1p(x)方法返回1 + x的自然對數,即Math.log(1 + x)。如果x小於-1,返回NaN
  • Math.log10(x)返回以 10 爲底的x的對數。如果x小於 0,則返回 NaN。
  • Math.log2(x)返回以 2 爲底的x的對數。如果x小於 0,則返回 NaN。

雙曲函數方法

ES6 新增了 6 個雙曲函數方法。

  • Math.sinh(x) 返回x的雙曲正弦(hyperbolic sine)
  • Math.cosh(x) 返回x的雙曲餘弦(hyperbolic cosine)
  • Math.tanh(x) 返回x的雙曲正切(hyperbolic tangent)
  • Math.asinh(x) 返回x的反雙曲正弦(inverse hyperbolic sine)
  • Math.acosh(x) 返回x的反雙曲餘弦(inverse hyperbolic cosine)
  • Math.atanh(x) 返回x的反雙曲正切(inverse hyperbolic tangent)

ES2016 新增了一個指數運算符(**),特點是右結合,而不是常見的左結合。多個指數運算符連用時,是從最右邊開始計算的。

2 ** 2 // 4
2 ** 3 // 8
// 相當於 2 ** (3 ** 2)
2 ** 3 ** 2
// 512

指數運算符可以與等號結合,形成一個新的賦值運算符(**=)。

let a = 1.5;
a **= 2;
// 等同於 a = a * a;

let b = 4;
b **= 3;
// 等同於 b = b * b * b;

 

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