ES6新语法之---函数扩展(7)

这节学习ES6中对函数新增的方法和属性。

1.新增函数的参数默认值

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

2.新增了函数的rest参数

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

3.length属性

  作用:获取函数预期传入的参数个数。

  指定默认值后,length属性将返回没有指定默认值参数的个数。

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

  注意:如果设置了默认值的参数不是尾参数,length属性也不再计入后面的参数。

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

4.严格模式

  严格模式是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中关于函数的扩展的属性和方法,还是需要多练习多理解。

  

 

posted @ 2018-07-29 23:58  诸葛不亮  阅读(1662)  评论(0编辑  收藏  举报