ES6新語法之---函數擴展(7)

這節學習ES6中對函數新增的方法和屬性。html

1.新增函數的參數默認值app

參考S6系列第二篇:http://www.cnblogs.com/diweikang/p/8976854.html函數

2.新增了函數的rest參數學習

參考ES6系列第二篇:http://www.cnblogs.com/diweikang/p/8976854.htmlthis

3.length屬性spa

  做用:獲取函數預期傳入的參數個數。prototype

  指定默認值後,length屬性將返回沒有指定默認值參數的個數。rest

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

  注意:若是設置了默認值的參數不是尾參數,length屬性也再也不計入後面的參數。code

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

4.嚴格模式htm

  嚴格模式是ES5中新增語法的,限制指定的代碼在更嚴格的模式下執行。一般在腳本開頭或函數頭部添加"use strict"表達式來聲明。

  <1>ES5開始,函數內部能夠顯示聲明嚴格模式。

    function doSomething(a, b) {
      'use strict';
      // ...
    }

  ES2016中規定,只要函數中使用了參數默認值、解構賦值、或者擴展運算符,函數內部就不容許顯示聲明嚴格模式,不然報錯。

    // 參數默認值
    function doSomething(a, b = a) {
         'use strict';
          // code
    }

    // 解構賦值
    const doSomething = function ({a, b}) {
      'use strict';
      // code
    };

    // 擴展運算符
    const doSomething = (...a) => {
      'use strict';
      // code
    };

    const obj = {
      // 解構賦值
      doSomething({a, b}) {
        'use strict';
        // code
      }
    };

  規定緣由:函數內部聲明的嚴格模式,限制函數參數和函數體都必須是嚴格模式執行。只有執行函數體的時候才能知道函數是不是嚴格模式,可是函數時先執行函數參數,再執行函數體的。這就致使參數若是不遵照嚴格模式,函數體中又顯示聲明嚴格模式,函數進行就會報錯。

    // 嚴格模式八進制使用0o前綴表示
    function doSomething(value = 070) {
      'use strict';
      return value;
    }

  上面函數執行就會報錯。

  如何規避這種限制:

    <1>、設定全局性的嚴格模式。

    'use strict';

    function doSomething(a, b = a) {
      // ...
    }

    <2>、把函數包裝在一個無參數的當即執行函數裏面。

    const doSomething = (function () {
      'use strict';
      return function(value = 42) {
        return value;
      };
    }());

5.name屬性

  ES6新增函數的name屬性,返回該函數的函數名。

  <1>將一個匿名函數賦值給一個變量,ES5的name屬性會返回空字符創,ES6的name屬性會返回實際的函數名稱。

    var f = function () {};
    // ES5
    f.name // ""
    // ES6
    f.name // "f"

  <2>將一個具名函數賦值給一個變量,ES5和ES6的name屬性都會返回這個具名函數的名稱。

    const bar = function baz() {};
    // ES5
    bar.name // "baz"
    // ES6
    bar.name // "baz"

  <3>構造函數返回的函數實例,name屬性值爲anonymous

    (new Function).name // "anonymous"

  <4>將bind返回的函數,name屬性值會加上bound前綴。

    function foo() {};
    foo.bind({}).name // "bound foo"

    (function(){}).bind({}).name // "bound "

6.箭頭函數

  ES6容許使用"箭頭"(=>)定義函數。

  <1>箭頭函數須要一個參數

    var f = v => v;

    // 等同於
    var f = function (v) {
      return v;
    };

  <2>箭頭函數不須要或者須要多個參數,使用括號將參數部分括起來。

    var f = () => 5;
    // 等同於
    var f = function () { return 5 };

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

  <3>箭頭函數代碼塊多餘一條語句,就要使用大括號括起來,並使用return語句返回。

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

  <4>若是箭頭函數須要返回一個對象對象外面須要小括號括起來,不然會被當成代碼塊返回。

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

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

  <5>若是箭頭函數只有一行語句,且不須要返回值,能夠採用下面的寫法。

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

  <6>箭頭函數與變量解構結合使用。

    const full = ({ first, last }) => first + ' ' + last;

    // 等同於
    function full(person) {
      return person.first + ' ' + person.last;
    }
    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]]

  <8>箭頭函數中的this對象。

  注意:箭頭函數中的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

  再看一個例子:

    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

  分析:箭頭函數中的this指向箭頭函數定義生效時所在的對象,第一個定時器中的this指向timer對象,第二個定時器指向調用它的對象(全局對象),3100ms後s1更新了3次,而s2並無更新,因此結果是3和0。

  總結:箭頭函數沒有自身的this對象。

    1.函數體中this對象,定義時所在的對象,不是函數調用時所在對象。

    2.不能夠當構造函數,也就是不可使用new命令。

    3.不可使用arguments對象,該對象在箭頭函數體內不存在。

  <9>雙冒號運算符

  ES6中提出使用雙冒號(::)函數綁定的運算符,替代call、apply、bind調用。

  雙冒號左邊是一個對象,右邊是一個方法,表示將右邊的函數綁定到左邊的對象上。

    foo::bar;
    // 等同於
    bar.bind(foo);
    
    foo::bar(...arguments);
    // 等同於
    bar.apply(foo, arguments);

    const hasOwnProperty = Object.prototype.hasOwnProperty;
    function hasOwn(obj, key) {
      return obj::hasOwnProperty(key);
    }

  雙冒號左邊爲空,右邊是一個對象的方法,表示將函數綁定到這個對象上。

    var method = obj::obj.foo;
    // 等同於
    var method = ::obj.foo;

    let log = ::console.log;
    // 等同於
    var log = console.log.bind(console);

總結:

  上面這些就是咱們在開發中,可能會用到的ES6中關於函數的擴展的屬性和方法,仍是須要多練習多理解。

相關文章
相關標籤/搜索