国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

ES6(2)-各種類型的擴展(字符串、正則、數值、函數)

godruoyi / 705人閱讀

摘要:返回布爾值,表示參數字符串是否在原字符串的頭部。模板字符串之中還能調用函數。其他對字符串還有許多擴展,例如對字符表示的擴充以及為字符串提供了遍歷方法詳情請點擊正則的擴展構造函數在中,構造函數的參數有兩種情況。

ES6對各種基本類型都做了擴展,內容有些多,本章節挑選比較重要的擴展說明。

1 字符串的擴展 1.1 includes(), startsWith(), endsWith()

傳統上,JavaScript只有indexOf方法,可以用來確定一個字符串是否包含在另一個字符串中。ES6又提供了三種新方法。

includes():返回布爾值,表示是否找到了參數字符串。

startsWith():返回布爾值,表示參數字符串是否在原字符串的頭部。

endsWith():返回布爾值,表示參數字符串是否在原字符串的尾部。

var s = "Hello world!";

s.startsWith("Hello") // true
s.endsWith("!") // true
s.includes("o") // true

這三個方法都支持第二個參數,表示開始搜索的位置。

var s = "Hello world!";

s.startsWith("world", 6) // true
s.endsWith("Hello", 5) // true
s.includes("Hello", 6) // false

上面代碼表示,使用第二個參數n時,endsWith的行為與其他兩個方法有所不同。它針對前n個字符,而其他兩個方法針對從第n個位置直到字符串結束。

1.2 repeat()

repeat方法返回一個新字符串,表示將原字符串重復n次。

"x".repeat(3) // "xxx"
"hello".repeat(2) // "hellohello"
"na".repeat(0) // ""

參數如果是小數,會被取整。

"na".repeat(2.9) // "nana"

如果repeat的參數是負數或者Infinity,會報錯。

"na".repeat(Infinity)
// RangeError
"na".repeat(-1)
// RangeError

但是,如果參數是0到-1之間的小數,則等同于0,這是因為會先進行取整運算。0到-1之間的小數,取整以后等于-0,repeat視同為0。

"na".repeat(-0.9) // ""

參數NaN等同于0。

"na".repeat(NaN) // ""

如果repeat的參數是字符串,則會先轉換成數字。

"na".repeat("na") // ""
"na".repeat("3") // "nanana"
1.3 模板字符串

這個功能應該是最值得介紹的了,因為有了這個,我們可以拋棄之前用 + 號拼接字符串了。

傳統的JavaScript語言,輸出模板通常是這樣寫的。

$("#result").append(
  "There are " + basket.count + " " +
  "items in your basket, " +
  "" + basket.onSale +
  " are on sale!"
);

上面這種寫法相當繁瑣不方便,而且改動麻煩,ES6引入了模板字符串解決這個問題。

$("#result").append(`
  There are ${basket.count} items
   in your basket, ${basket.onSale}
  are on sale!
`);

模板字符串(template string)是增強版的字符串,用反引號(`)標識。它可以當作普通字符串使用,也可以用來定義多行字符串,或者在字符串中嵌入變量。

// 普通字符串
`In JavaScript "
" is a line-feed.`

// 多行字符串
`In JavaScript this is
 not legal.`

console.log(`string text line 1
string text line 2`);

// 字符串中嵌入變量
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

上面代碼中的模板字符串,都是用反引號表示。如果在模板字符串中需要使用反引號,則前面要用反斜杠轉義。

var greeting = ``Yo` World!`;

如果使用模板字符串表示多行字符串,所有的空格和縮進都會被保留在輸出之中。

$("#list").html(`
  • first
  • second
`);

上面代碼中,所有模板字符串的空格和換行,都是被保留的,比如

    標簽前面會有一個換行。如果你不想要這個換行,可以使用trim方法消除它。

    $("#list").html(`
    
    • first
    • second
    `.trim());

    模板字符串中嵌入變量,需要將變量名寫在${}之中。

    function authorize(user, action) {
      if (!user.hasPrivilege(action)) {
        //傳統寫法為
        //return "str:" + a + "XXXX"; 
        return  `str: ${a} XXXX`);
      }
    }
    

    大括號內部可以放入任意的JavaScript表達式,可以進行運算,以及引用對象屬性。

    var x = 1;
    var y = 2;
    
    `${x} + ${y} = ${x + y}`
    // "1 + 2 = 3"
    
    `${x} + ${y * 2} = ${x + y * 2}`
    // "1 + 4 = 5"
    
    var obj = {x: 1, y: 2};
    `${obj.x + obj.y}`
    // "3"
    

    模板字符串之中還能調用函數。

    function fn() {
      return "Hello World";
    }
    
    `foo ${fn()} bar`
    // foo Hello World bar
    

    如果大括號中的值不是字符串,將按照一般的規則轉為字符串。比如,大括號中是一個對象,將默認調用對象的toString方法。

    如果模板字符串中的變量沒有聲明,將報錯。

    // 變量place沒有聲明
    var msg = `Hello, ${place}`;
    // 報錯
    

    由于模板字符串的大括號內部,就是執行JavaScript代碼,因此如果大括號內部是一個字符串,將會原樣輸出。

    `Hello ${"World"}`
    // "Hello World"
    

    模板字符串甚至還能嵌套。

    const tmpl = addrs => `
      
      ${addrs.map(addr => `
        
      `).join("")}
      
    ${addr.first}
    ${addr.last}
    `; //上面代碼中,模板字符串的變量之中,又嵌入了另一個模板字符串,使用方法如下。 const data = [ { first: "", last: "Bond" }, { first: "Lars", last: "" }, ]; console.log(tmpl(data)); // // // // // // // // //
    Bond
    Lars
    1.4 其他

    ES6對字符串還有許多擴展,例如 對 字符Unicode表示的擴充以及為字符串提供了遍歷方法(for ... of)
    詳情請點擊 http://es6.ruanyifeng.com/#do...

    2 正則的擴展 2.1 RegExp 構造函數

    在 ES5 中,RegExp構造函數的參數有兩種情況。

    第一種情況是,參數是字符串,這時第二個參數表示正則表達式的修飾符(flag)。

    var regex = new RegExp("xyz", "i");
    // 等價于
    var regex = /xyz/i;
    

    第二種情況是,參數是一個正則表示式,這時會返回一個原有正則表達式的拷貝。

    var regex = new RegExp(/xyz/i);
    // 等價于
    var regex = /xyz/i;
    

    但是,ES5 不允許此時使用第二個參數添加修飾符,否則會報錯。

    var regex = new RegExp(/xyz/, "i");
    // Uncaught TypeError: Cannot supply flags when constructing one RegExp from another
    

    ES6 改變了這種行為。如果RegExp構造函數第一個參數是一個正則對象,那么可以使用第二個參數指定修飾符。而且,返回的正則表達式會忽略原有的正則表達式的修飾符,只使用新指定的修飾符。

    new RegExp(/abc/ig, "i").flags
    // "i"
    

    上面代碼中,原有正則對象的修飾符是ig,它會被第二個參數i覆蓋。

    2.2 新的修飾符-u

    ES6 對正則表達式添加了u修飾符,含義為“Unicode模式”,用來正確處理大于uFFFF的 Unicode 字符。也就是說,會正確處理四個字節的 UTF-16 編碼。

    /^uD83D/u.test("uD83DuDC2A") // false
    /^uD83D/.test("uD83DuDC2A") // true
    

    上面代碼中,uD83DuDC2A是一個四個字節的 UTF-16 編碼,代表一個字符。但是,ES5 不支持四個字節的 UTF-16 編碼,會將其識別為兩個字符,導致第二行代碼結果為true。加了u修飾符以后,ES6 就會識別其為一個字符,所以第一行代碼結果為false。

    2.3 新的修飾符-y

    除了u修飾符,ES6 還為正則表達式添加了y修飾符,叫做“粘連”(sticky)修飾符。

    y修飾符的作用與g修飾符類似,也是全局匹配,后一次匹配都從上一次匹配成功的下一個位置開始。不同之處在于,g修飾符只要剩余位置中存在匹配就可,而y修飾符確保匹配必須從剩余的第一個位置開始,這也就是“粘連”的涵義。

    var s = "aaa_aa_a";
    var r1 = /a+/g;
    var r2 = /a+/y;
    
    r1.exec(s) // ["aaa"]
    r2.exec(s) // ["aaa"]
    
    r1.exec(s) // ["aa"]
    r2.exec(s) // null
    

    上面代碼有兩個正則表達式,一個使用g修飾符,另一個使用y修飾符。這兩個正則表達式各執行了兩次,第一次執行的時候,兩者行為相同,剩余字符串都是_aa_a。由于g修飾沒有位置要求,所以第二次執行會返回結果,而y修飾符要求匹配必須從頭部開始,所以返回null。

    如果改一下正則表達式,保證每次都能頭部匹配,y修飾符就會返回結果了。

    var s = "aaa_aa_a";
    var r = /a+_/y;
    
    r.exec(s) // ["aaa_"]
    r.exec(s) // ["aa_"]
    
    3 數值的擴展 3.1 Number.isFinite(), Number.isNaN()

    ES6 在Number對象上,新提供了Number.isFinite()和Number.isNaN()兩個方法。

    Number.isFinite()用來檢查一個數值是否為有限的(finite)。

    Number.isFinite(15); // true
    Number.isFinite(0.8); // true
    Number.isFinite(NaN); // false
    Number.isFinite(Infinity); // false
    Number.isFinite(-Infinity); // false
    Number.isFinite("foo"); // false
    Number.isFinite("15"); // false
    Number.isFinite(true); // false
    

    ES5 可以通過下面的代碼,部署Number.isFinite方法。

    (function (global) {
      var global_isFinite = global.isFinite;
    
      Object.defineProperty(Number, "isFinite", {
        value: function isFinite(value) {
          return typeof value === "number" && global_isFinite(value);
        },
        configurable: true,
        enumerable: false,
        writable: true
      });
    })(this);
    

    Number.isNaN()用來檢查一個值是否為NaN。

    Number.isNaN(NaN) // true
    Number.isNaN(15) // false
    Number.isNaN("15") // false
    Number.isNaN(true) // false
    Number.isNaN(9/NaN) // true
    Number.isNaN("true"/0) // true
    Number.isNaN("true"/"true") // true
    

    ES5 通過下面的代碼,部署Number.isNaN()

    (function (global) {
      var global_isNaN = global.isNaN;
    
      Object.defineProperty(Number, "isNaN", {
        value: function isNaN(value) {
          return typeof value === "number" && global_isNaN(value);
        },
        configurable: true,
        enumerable: false,
        writable: true
      });
    })(this);
    

    它們與傳統的全局方法isFinite()isNaN()的區別在于,傳統方法先調用Number()將非數值的值轉為數值,再進行判斷,而這兩個新方法只對數值有效,Number.isFinite()對于非數值一律返回false, Number.isNaN()只有對于NaN才返回true,非NaN一律返回false。

    isFinite(25) // true
    isFinite("25") // true
    Number.isFinite(25) // true
    Number.isFinite("25") // false
    
    isNaN(NaN) // true
    isNaN("NaN") // true
    Number.isNaN(NaN) // true
    Number.isNaN("NaN") // false
    Number.isNaN(1) // false
    
    3.2 Number.parseInt(), Number.parseFloat()

    ES6 將全局方法parseInt()和parseFloat(),移植到Number對象上面,行為完全保持不變。

    // ES5的寫法
    parseInt("12.34") // 12
    parseFloat("123.45#") // 123.45
    
    // ES6的寫法
    Number.parseInt("12.34") // 12
    Number.parseFloat("123.45#") // 123.45
    

    這樣做的目的,是逐步減少全局性方法,使得語言逐步模塊化。

    Number.parseInt === parseInt // true
    Number.parseFloat === parseFloat // true
    
    3.3 Number.isInteger()

    Number.isInteger()用來判斷一個值是否為整數。需要注意的是,在 JavaScript 內部,整數和浮點數是同樣的儲存方法,所以3和3.0被視為同一個值。

    Number.isInteger(25) // true
    Number.isInteger(25.0) // true
    Number.isInteger(25.1) // false
    Number.isInteger("15") // false
    Number.isInteger(true) // false
    

    ES5 可以通過下面的代碼,部署Number.isInteger()

    (function (global) {
      var floor = Math.floor,
        isFinite = global.isFinite;
    
      Object.defineProperty(Number, "isInteger", {
        value: function isInteger(value) {
          return typeof value === "number" &&
            isFinite(value) &&
            floor(value) === value;
        },
        configurable: true,
        enumerable: false,
        writable: true
      });
    })(this);
    
    4 函數的擴展 4.1 函數參數的默認值

    基本用法

    ES6 之前,不能直接為函數的參數指定默認值,只能采用變通的方法。

    function log(x, y) {
      y = y || "World";
      console.log(x, y);
    }
    
    log("Hello") // Hello World
    log("Hello", "China") // Hello China
    log("Hello", "") // Hello World
    

    上面代碼檢查函數log的參數y有沒有賦值,如果沒有,則指定默認值為World。這種寫法的缺點在于,如果參數y賦值了,但是對應的布爾值為false,則該賦值不起作用。就像上面代碼的最后一行,參數y等于空字符,結果被改為默認值。

    為了避免這個問題,通常需要先判斷一下參數y是否被賦值,如果沒有,再等于默認值。

    if (typeof y === "undefined") {
      y = "World";
    }
    

    ES6 允許為函數的參數設置默認值,即直接寫在參數定義的后面。

    function log(x, y = "World") {
      console.log(x, y);
    }
    
    log("Hello") // Hello World
    log("Hello", "China") // Hello China
    log("Hello", "") // Hello
    

    可以看到,ES6 的寫法比 ES5 簡潔許多,而且非常自然。

    除了簡潔,ES6 的寫法還有兩個好處:首先,閱讀代碼的人,可以立刻意識到哪些參數是可以省略的,不用查看函數體或文檔;其次,有利于將來的代碼優化,即使未來的版本在對外接口中,徹底拿掉這個參數,也不會導致以前的代碼無法運行。

    參數變量是默認聲明的,所以不能用let或const再次聲明。

    function foo(x = 5) {
      let x = 1; // error
      const x = 2; // error
    }
    

    上面代碼中,參數變量x是默認聲明的,在函數體中,不能用let或const再次聲明,否則會報錯。

    使用參數默認值時,函數不能有同名參數。

    // 不報錯
    function foo(x, x, y) {
      // ...
    }
    
    // 報錯
    function foo(x, x, y = 1) {
      // ...
    }
    // SyntaxError: Duplicate parameter name not allowed in this context
    

    另外,一個容易忽略的地方是,參數默認值不是傳值的,而是每次都重新計算默認值表達式的值。也就是說,參數默認值是惰性求值的。

    let x = 99;
    function foo(p = x + 1) {
      console.log(p);
    }
    
    foo() // 100
    
    x = 100;
    foo() // 101
    

    上面代碼中,參數p的默認值是x + 1。這時,每次調用函數foo,都會重新計算x + 1,而不是默認p等于 100。

    參數默認值的位置

    通常情況下,定義了默認值的參數,應該是函數的尾參數。因為這樣比較容易看出來,到底省略了哪些參數。如果非尾部的參數設置默認值,實際上這個參數是沒法省略的。

    // 例一
    function f(x = 1, y) {
      return [x, y];
    }
    
    f() // [1, undefined]
    f(2) // [2, undefined])
    f(, 1) // 報錯
    f(undefined, 1) // [1, 1]
    
    // 例二
    function f(x, y = 5, z) {
      return [x, y, z];
    }
    
    f() // [undefined, 5, undefined]
    f(1) // [1, 5, undefined]
    f(1, ,2) // 報錯
    f(1, undefined, 2) // [1, 5, 2]
    

    上面代碼中,有默認值的參數都不是尾參數。這時,無法只省略該參數,而不省略它后面的參數,除非顯式輸入undefined。

    如果傳入undefined,將觸發該參數等于默認值,null則沒有這個效果。

    function foo(x = 5, y = 6) {
      console.log(x, y);
    }
    
    foo(undefined, null)
    // 5 null
    

    上面代碼中,x參數對應undefined,結果觸發了默認值,y參數等于null,就沒有觸發默認值。

    函數的 length 屬性

    指定了默認值以后,函數的length屬性,將返回沒有指定默認值的參數個數。也就是說,指定了默認值后,length屬性將失真。

    (function (a) {}).length // 1
    (function (a = 5) {}).length // 0
    (function (a, b, c = 5) {}).length // 2
    

    上面代碼中,length屬性的返回值,等于函數的參數個數減去指定了默認值的參數個數。比如,上面最后一個函數,定義了3個參數,其中有一個參數c指定了默認值,因此length屬性等于3減去1,最后得到2。

    這是因為length屬性的含義是,該函數預期傳入的參數個數。某個參數指定默認值以后,預期傳入的參數個數就不包括這個參數了。同理,后文的 rest 參數也不會計入length屬性。

    (function(...args) {}).length // 0
    

    如果設置了默認值的參數不是尾參數,那么length屬性也不再計入后面的參數了。

    (function (a = 0, b, c) {}).length // 0
    (function (a, b = 1, c) {}).length // 1
    

    作用域

    一旦設置了參數的默認值,函數進行聲明初始化時,參數會形成一個多帶帶的作用域(context)。等到初始化結束,這個作用域就會消失。這種語法行為,在不設置參數默認值時,是不會出現的。

    var x = 1;
    
    function f(x, y = x) {
      console.log(y);
    }
    
    f(2) // 2
    

    上面代碼中,參數y的默認值等于變量x。調用函數f時,參數形成一個多帶帶的作用域。在這個作用域里面,默認值變量x指向第一個參數x,而不是全局變量x,所以輸出是2。

    再看下面的例子。

    let x = 1;
    
    function f(y = x) {
      let x = 2;
      console.log(y);
    }
    
    f() // 1
    

    上面代碼中,函數f調用時,參數y = x形成一個多帶帶的作用域。這個作用域里面,變量x本身沒有定義,所以指向外層的全局變量x。函數調用時,函數體內部的局部變量x影響不到默認值變量x。

    如果此時,全局變量x不存在,就會報錯。

    function f(y = x) {
      let x = 2;
      console.log(y);
    }
    
    f() // ReferenceError: x is not defined
    

    下面這樣寫,也會報錯。

    var x = 1;
    
    function foo(x = x) {
      // ...
    }
    
    foo() // ReferenceError: x is not defined
    

    上面代碼中,參數x = x形成一個多帶帶作用域。實際執行的是let x = x,由于暫時性死區的原因,這行代碼會報錯”x 未定義“。

    4.2 rest 參數

    ES6 引入 rest 參數(形式為...變量名),用于獲取函數的多余參數,這樣就不需要使用arguments對象了。rest 參數搭配的變量是一個數組,該變量將多余的參數放入數組中。

    function add(...values) {
      let sum = 0;
    
      for (var val of values) {
        sum += val;
      }
    
      return sum;
    }
    
    add(2, 5, 3) // 10
    

    上面代碼的add函數是一個求和函數,利用 rest 參數,可以向該函數傳入任意數目的參數。

    下面是一個 rest 參數代替arguments變量的例子。

    // arguments變量的寫法
    function sortNumbers() {
      return Array.prototype.slice.call(arguments).sort();
    }
    
    // rest參數的寫法
    const sortNumbers = (...numbers) => numbers.sort();
    

    上面代碼的兩種寫法,比較后可以發現,rest 參數的寫法更自然也更簡潔。

    rest 參數中的變量代表一個數組,所以數組特有的方法都可以用于這個變量。下面是一個利用 rest 參數改寫數組push方法的例子。

    function push(array, ...items) {
      items.forEach(function(item) {
        array.push(item);
        console.log(item);
      });
    }
    
    var a = [];
    push(a, 1, 2, 3)
    

    注意,rest 參數之后不能再有其他參數(即只能是最后一個參數),否則會報錯。

    // 報錯
    function f(a, ...b, c) {
      // ...
    }
    

    函數的length屬性,不包括 rest 參數。

    (function(a) {}).length  // 1
    (function(...a) {}).length  // 0
    (function(a, ...b) {}).length  // 1
    
    4.3 箭頭函數

    基本用法

    ES6 允許使用“箭頭”(=>)定義函數。

    var f = v => v;
    

    上面的箭頭函數等同于:

    var f = function(v) {
      return v;
    };
    

    如果箭頭函數不需要參數或需要多個參數,就使用一個圓括號代表參數部分。

    var f = () => 5;
    // 等同于
    var f = function () { return 5 };
    
    var sum = (num1, num2) => num1 + num2;
    // 等同于
    var sum = function(num1, num2) {
      return num1 + num2;
    };
    

    如果箭頭函數的代碼塊部分多于一條語句,就要使用大括號將它們括起來,并且使用return語句返回。

    var sum = (num1, num2) => { return num1 + num2; }
    

    由于大括號被解釋為代碼塊,所以如果箭頭函數直接返回一個對象,必須在對象外面加上括號,否則會報錯。

    // 報錯
    let getTempItem = id => { id: id, name: "Temp" };
    
    // 不報錯
    let getTempItem = id => ({ id: id, name: "Temp" });
    

    如果箭頭函數只有一行語句,且不需要返回值,可以采用下面的寫法,就不用寫大括號了。

    let fn = () => void doesNotReturn();
    

    箭頭函數可以與變量解構結合使用。

    const full = ({ first, last }) => first + " " + last;
    
    // 等同于
    function full(person) {
      return person.first + " " + person.last;
    }
    

    箭頭函數使得表達更加簡潔。

    const isEven = n => n % 2 == 0;
    const square = n => n * n;
    

    上面代碼只用了兩行,就定義了兩個簡單的工具函數。如果不用箭頭函數,可能就要占用多行,而且還不如現在這樣寫醒目。

    箭頭函數的一個用處是簡化回調函數。

    // 正常函數寫法
    [1,2,3].map(function (x) {
      return x * x;
    });
    
    // 箭頭函數寫法
    [1,2,3].map(x => x * x);
    

    另一個例子是

    // 正常函數寫法
    var result = values.sort(function (a, b) {
      return a - b;
    });
    
    // 箭頭函數寫法
    var result = values.sort((a, b) => a - b);
    下面是 rest 參數與箭頭函數結合的例子。
    
    const numbers = (...nums) => nums;
    
    numbers(1, 2, 3, 4, 5)
    // [1,2,3,4,5]
    
    const headAndTail = (head, ...tail) => [head, tail];
    
    headAndTail(1, 2, 3, 4, 5)
    // [1,[2,3,4,5]]
    

    使用注意點

    箭頭函數有幾個使用注意點。

    (1)函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。

    (2)不可以當作構造函數,也就是說,不可以使用new命令,否則會拋出一個錯誤。

    (3)不可以使用arguments對象,該對象在函數體內不存在。如果要用,可以用 rest 參數代替。

    (4)不可以使用yield命令,因此箭頭函數不能用作 Generator 函數。

    上面四點中,第一點尤其值得注意。this對象的指向是可變的,但是在箭頭函數中,它是固定的。

    function foo() {
      setTimeout(() => {
        console.log("id:", this.id);
      }, 100);
    }
    
    var id = 21;
    
    foo.call({ id: 42 });
    // id: 42
    

    上面代碼中,setTimeout的參數是一個箭頭函數,這個箭頭函數的定義生效是在foo函數生成時,而它的真正執行要等到100毫秒后。如果是普通函數,執行時this應該指向全局對象window,這時應該輸出21。但是,箭頭函數導致this總是指向函數定義生效時所在的對象(本例是{id: 42}),所以輸出的是42。

    箭頭函數可以讓setTimeout里面的this,綁定定義時所在的作用域,而不是指向運行時所在的作用域。下面是另一個例子。

    function Timer() {
      this.s1 = 0;
      this.s2 = 0;
      // 箭頭函數
      setInterval(() => this.s1++, 1000);
      // 普通函數
      setInterval(function () {
        this.s2++;
      }, 1000);
    }
    
    var timer = new Timer();
    
    setTimeout(() => console.log("s1: ", timer.s1), 3100);
    setTimeout(() => console.log("s2: ", timer.s2), 3100);
    // s1: 3
    // s2: 0
    

    上面代碼中,Timer函數內部設置了兩個定時器,分別使用了箭頭函數和普通函數。前者的this綁定定義時所在的作用域(即Timer函數),后者的this指向運行時所在的作用域(即全局對象)。所以,3100毫秒之后,timer.s1被更新了3次,而timer.s2一次都沒更新。

    箭頭函數可以讓this指向固定化,這種特性很有利于封裝回調函數。下面是一個例子,DOM 事件的回調函數封裝在一個對象里面。

    var handler = {
      id: "123456",
    
      init: function() {
        document.addEventListener("click",
          event => this.doSomething(event.type), false);
      },
    
      doSomething: function(type) {
        console.log("Handling " + type  + " for " + this.id);
      }
    };
    

    上面代碼的init方法中,使用了箭頭函數,這導致這個箭頭函數里面的this,總是指向handler對象。否則,回調函數運行時,this.doSomething這一行會報錯,因為此時this指向document對象。

    this指向的固定化,并不是因為箭頭函數內部有綁定this的機制,實際原因是箭頭函數根本沒有自己的this,導致內部的this就是外層代碼塊的this。正是因為它沒有this,所以也就不能用作構造函數。

    所以,箭頭函數轉成 ES5 的代碼如下。

    // ES6
    function foo() {
      setTimeout(() => {
        console.log("id:", this.id);
      }, 100);
    }
    
    // ES5
    function foo() {
      var _this = this;
    
      setTimeout(function () {
        console.log("id:", _this.id);
      }, 100);
    }
    

    上面代碼中,轉換后的ES5版本清楚地說明了,箭頭函數里面根本沒有自己的this,而是引用外層的this。

    除了this,arguments在箭頭函數之中也是不存在的,它是指向外層函數的對應變量。

    function foo() {
      setTimeout(() => {
        console.log("args:", arguments);
      }, 100);
      setTimeout(function() {
        console.log("args:", arguments);
      }, 100);
    }
    
    foo(2, 4, 6, 8)
    // args: [2, 4, 6, 8]
    

    上面代碼中,箭頭函數內部的變量arguments,其實是函數foo的arguments變量。

    另外,由于箭頭函數沒有自己的this,所以當然也就不能用call()、apply()、bind()這些方法去改變this的指向。

    (function() {
      return [
        (() => this.x).bind({ x: "inner" })()
      ];
    }).call({ x: "outer" });
    // ["outer"]
    

    上面代碼中,箭頭函數沒有自己的this,所以bind方法無效,內部的this指向外部的this。

    長期以來,JavaScript 語言的this對象一直是一個令人頭痛的問題,在對象方法中使用this,必須非常小心。箭頭函數”綁定”this,很大程度上解決了這個困擾。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/85065.html

相關文章

  • ES6學習筆記2—各擴展

    摘要:字符串的擴展字符的表示法允許采用形式表示一個字符,其中表示字符的碼點。返回布爾值,表示參數字符串是否在源字符串的頭部。使用和這兩個常量,用來表示這個范圍的上下限。對于那些無法用個二進制位精確表示的小數,方法返回最接近這個小數的單精度浮點數。 字符串的擴展 字符的 Unicode 表示法 JavaScript 允許采用uxxxx形式表示一個字符,其中xxxx表示字符的 Unicode 碼...

    Zoom 評論0 收藏0
  • ES6標準入門》讀書筆記

    摘要:標準入門讀書筆記和命令新增命令,用于聲明變量,是塊級作用域。用于頭部補全,用于尾部補全。函數調用的時候會在內存形成一個調用記錄,又稱為調用幀,保存調用位置和內部變量等信息。等到執行結束再返回給,的調用幀才消失。 《ES6標準入門》讀書筆記 @(StuRep) showImg(https://segmentfault.com/img/remote/1460000006766369?w=3...

    HollisChuang 評論0 收藏0
  • ES6

    摘要:情況一情況二這兩種情況,根據的規定都是非法的。的作用域與命令相同只在聲明所在的塊級作用域內有效。因此,將一個對象聲明為常量必須非常小心。頂層對象的屬性與全局變量掛鉤,被認為時語言最大的設計敗筆之一。 這是ES6的入門篇教程的筆記,網址:鏈接描述,以下內容中粗體+斜體表示大標題,粗體是小標題,還有一些重點;斜體表示對于自身,還需要下功夫學習的內容。這里面有一些自己的見解,所以若是發現問題...

    AZmake 評論0 收藏0
  • 深入理解ES6(三)(符串擴展

    摘要:字符串的擴展一字符串的遍歷器接口為字符串添加了遍歷器接口,使得字符串可以被循環遍歷。返回布爾值,表示參數字符串是否在源字符串的頭部。三方法返回一個新字符串,表示將原字符串重復次。如果模板字符串中的變量沒有聲明,將報錯。 字符串的擴展 一、 字符串的遍歷器接口 ES6 為字符串添加了遍歷器接口,使得字符串可以被for...of循環遍歷。 for (let codePoint of foo...

    Steve_Wang_ 評論0 收藏0
  • 深入理解ES6(三)(符串擴展

    摘要:字符串的擴展一字符串的遍歷器接口為字符串添加了遍歷器接口,使得字符串可以被循環遍歷。返回布爾值,表示參數字符串是否在源字符串的頭部。三方法返回一個新字符串,表示將原字符串重復次。如果模板字符串中的變量沒有聲明,將報錯。 字符串的擴展 一、 字符串的遍歷器接口 ES6 為字符串添加了遍歷器接口,使得字符串可以被for...of循環遍歷。 for (let codePoint of foo...

    tainzhi 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<