首页 > 其他 > 详细

ES6之函数

时间:2019-11-18 18:35:39      阅读:70      评论:0      收藏:0      [点我收藏+]

ES6之函数

本文知识点主要有:

  • 函数默认参数
  • 展开运算符
  • 函数的其他优化
  • 箭头函数
  • 尾调用的内存优化

函数参数默认值

ES6之前,函数对与参数的默认值设置通常采用以下方式:

  function makeRequest (url, timeout, callback) {
    timeout = timeout || 2000;
      callback = callback || function () {};
      // ...
  }

但此方法有个小缺陷,就是timeout在传入 0 / false 时,都会默认采用2000。对此进行优化如下:

  function makeRequest (url, timeout, callback) {
      timeout = (typeof timeout !== "undefined") ? timeout : 2000;
      callback = (typeof callback !== "undefined") ? callback : functipn () {};
    // ...
  }

上段代码中 undefined也可以换成void 0
看起来仍旧有点繁琐。为此,ES6提供了默认参数值的用法,更改如下:

  function makeRequest (url, timeout = 2000, callback = function () {} {
    // ... 
  }

看起来简洁了很多。代码中,url是必填值,timeout 和 callback是可选参数。可以选择不传、或者传undefined让其使用默认值。
此外,参数默认值也可以写成表达式。

  function add (first, second = getValue(first)) {
        return first + second;
  }
    function getValue(num) {
        return num + 1
    }
    add(1, 1)  // 2
    add(1)     // 3

second的默认参数值,使用了first,且调用了getValue函数。值得注意的是,默认参数也存在临时死区,即未声明变量之前,无法进行访问。

    function add (first, second = first) {}

  等价于
    
    function add () {
        let first = arguments[0];
        let second = first;
        {
            // 函数体
        }
    }

参数的默认值是不可以访问函数体内声明的变量。因此,需要用代码块的形式将其隔离。

对于 arguments 的影响

在ES5 非严格模式中。arguments会随着形参被重新赋值进行改变。

    function mixArgs (first, second) {
        console.log(first === arguments[0]);
        console.log(second === arguments[1]);
        first = 'c';
        second = 'd';
        console.log(first === arguments[0]);
        console.log(second === arguments[1]);
    }
    mixArgs("a", "b");  
  // true true true true

ES5严格模式时,arguments便不会随着形参被重新赋值进行改变。ES6 与ES5严格模式保持一致。

展开运算符

展开运算符由三个点组成 ( … ),主要有两种用途:

  • 函数参数的收集
  • 数据展开

函数参数的收集

arguments相同,可以收集传入函数中的多个无命名参数。不同点有以下几点:

  • arguments为一个类数组集合,而 … 为数组
  • arguments在形参声明时,可以省略。而 … 必须声明,且只能声明一个放在形参的最后。
  • arguments收集所有的参数。而 … 只收集其他形参声明后,剩余的参数。

最后, …不能在setter 函数中使用,set函数只能有一个参数。

  function add (...args) {
        let sum = 0;
        for (let i = 0; i < args.length; i++) {
            sum += args[i]
        }
  }
    add(1, 2, 3, 4, 5, 6); // 21

数据展开

展开运算符可以简化给函数传参的过程, 大多数使用apply() 方法的情况,使用展开运算符会更方便。

    let values = [21, 50, 75, 100];

    console.log(Math.max(...values));
    console.log(Math.max.apply(Math, values));

    // 100 100

函数的其他优化

  • 增强的Function构造函数 。我们可以在Function中使用默认参数和展开运算符。
    var add = new Function("first", "second = first", "...args", "return first + second");
    console.log(add(1, 2);
  • name属性:用于便于辨识函数。
    function func1 () { //... };

    var func2 = function () { // ... };

    var func3 = function func4 () { // ... };

    var person = {
        get func5 () { // ... }
    };
    var func6 = Object.getOwnPropertyDescriptor(person, "func5"); 

    console.log(func1.name);            // func1
    console.log(func2.name);            // func2
    console.log(func3.name);            // func4 (函数声明权重较高)
    console.log(func6.get.name);     // get func6

    console.log(func1.bind().name);     // bound func1

    console.log((new Function()).name); // anonymos

最后的四个console的结果需要注意。由于函数提升原则,函数的name值被提前绑定。而set(get)函数,保留其前缀。同样的,使用bind会产生bound前缀。使用Function构造函数的匿名函数,其name值为anonymos

  • new.target
    当使用new关键字调用函数时,会默认执行函数的[[Construct]]函数,创建一个实例的新对象,然后执行函数体。最后将this绑定到新对象上完成创建过程。
    不通过new关键字调用函数时,会执行函数的[[Call]]函数,直接执行函数体。
    ES6在函数中新增的new.target就为了判断函数是否通过new进行调用。
    function Person(name) {
        if (typeof new.target !== 'undefined') {
            this.name = name;
        } else {
            throw new Error("必须通过new关键字来调用Person")
        }
    }
  var p1 = new Person("leo");     
    var p2 = Person(p1); // 报错 
    var p3 = Person.call(p1, "leo"); // 报错

箭头函数

与传统的函数相比,有以下几个方面的不同:

  • arguments, new.target的绑定.
  • 不能使用 new关键字进行调用。(因为没有 [[Construct]]构造方法)
  • 没有原型,不存在prototype属性,
  • 不能改变this的指向。
  • 参数不能重名
    var sum = function (num1, num2)  => num1 + num2;

箭头函数的写法有以下简写规则:

  • 没有参数时,使用一对空的小括号 () => {}
  • 有一个参数时,直接使用 : 参数名 =>
  • 有两以上参数,用括号包裹: (参数1, 参数2) => {}
  • 只有一条执行语句时,函数体的花括号和return可以省略: () => 1

箭头函数更加纯粹,简洁且易用的表示方式应普遍使用。

  • 尾调函数的内存优化
    在递归,闭包函数通常会使用更多的内存来保存作用域,产生栈堆的大量占用。ES6对此进行优化,让重复的函数只使用一个栈堆。为了使用此内存的优化,需要符合以下的规则:
    • 尾调函数不访问当前栈内的变量(非闭包函数)
    • 尾调函数为最后一条语句
    • 尾调用的结果作为函数值返回

举例熟悉的斐波拉切函数

    "use strict";
    function factorila(n) {
        if (n <= 1) {
            return 1;
        } else {
            return n * factorila(n - 1);    
        }
    }

可优化为:

    "use strict";
    function factorila(n, p - 1) {
        if (n <= 1) {
            return 1 * p;
        } else {
            let result = n * p;
            return factorila(n - 1, result);    
        }
    }

ES6之函数

原文:https://www.cnblogs.com/miku561/p/11883939.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!