美文网首页前端
函数的扩展

函数的扩展

作者: 前白 | 来源:发表于2019-08-13 10:09 被阅读5次

    这篇文章主要介绍了函数的扩展,函数的扩展只要有三个方面:

    • 参数的默认值
    • 箭头函数
    • 关于尾调用的优化

    1:参数的默认值(会形成一个单独的作用域)

    可以在直接定义函数的时候,定义好参数如果没传或者传错 undefined。

        //解构的基本用法
        //用法1:
        function log(x, y = 'World') {
            console.log(x, y);
        }
        
        log('Hello');
        //Hello World
        
        log('Hello', 'China');
        /* Hello China */
        
        log('Hello', '');
        /* Hello */
        
        参数的默认值只有在没传时才会生效。
        //用法2:
        function week({ x, y = 5 }) {
            console.log(x, y);
        }
        
        week({});
        /* undefined 5 */
        
        week({x: 1});
        /* 1 5 */
        
        week({x: 1, y: 2});
        /* 1 2 */
        
        week();
        /* TypeError: Cannot read property 'x' of undefined */
        
        //用法3:
        function week({x, y = 5} = {}) {
            console.log(x, y);
        }
        
        week();
        /* undefined 5 */
    

    解构和参数的默认值需要注意的点:

    • 参数的变量已经默认声明,不能用let或const再次声明
         function week(x = 5) {
             let x = 1;
             const x = 2;
         }
         /* SyntaxError: Identifier 'x' has already been declared */
      
    • 函数不能有同名参数,因为参数的变量已经默认声明所以不能再次声明
         function week(x, x, y = 1) {
             /* ... */
         }
         /* SyntaxError: Duplicate parameter name not allowed in this context */
      
    • 参数默认值是惰性求值
      当我们真正运算走这个函数的时候,它才会去处理默认的参数
         let x = 99;
         function week(p = x + 1) {
             console.log(p);
         }
         
         week();
         /* 100 */
         
         x = 100;
         week();
         /* 101 */
      
    • 参数默认值一般用于尾部,比如一个函数
    • length属性,也就是函数的name和let,返回没有指定默认值的参数个数
         (function (a) {}).length;
         //1
         
         (function (a = 5) {}).length;
         //0
         
         (function (a, b, c = 5) {}).length;
         //2
         
         (function (a = 0, b, c) {}).length;
         //0
         
         (function (a, b = 1, c) {}).length;
         //1
         
         (function(...args) {}).length;
         //0
      
    • 设置了参数的默认值,参数会形成一个单独的作用域
         var x = 1;
         function f(x, y = x) {
             console.log(y);
         }
         
         f(2);
         //2
         
         let x = 1;
         function f(y = x) {
             let x = 2;
             console.log(y);
         }
         
         f();
         //1
      

    2:rest参数,只能有一个参数,部分场景可以替代argument、类似于argument。

    比如一个函数的argument我们知道这是函数的参数,argument实际上是官方不推荐的一种用法。

        function add(...values) {
        let sum = 0;
        
        for (var val of values) {
            sum += val;
        }
        
        return sum;
        }
        
        add(2, 5, 3);
        /* 10 */
        
        function sortNumbers() {
            return Array.prototype.slice.call(arguments).sort();
        }
        
        const sortNumbers = (...numbers) => numbers.sort();
    

    3:严格模式,在严格模式下,使用了默认值、解构赋值或者扩展不能使用严格模式。

    4:name 返回函数名

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

    5:箭头函数

    箭头函数主要的两点是:第一点它的this指向是在它当时定义所在的作用域,第二个是它没有一个作用域的提升。

        // 单个参数 
        var f = v => v;
        var f = function (v) {
            return v;
        };
        
        // 多个参数 
        var sum = (num1, num2) => num1 + num2;
        var sum = function(num1, num2) {
            return num1 + num2;
        };
       
        // return,有两种场景,箭头函数里面直接写return
        // 或者不写的话箭头函数就会默认把这个结果当成一个return。
        // 也就是说当我们返回一个对象时,没有return语句的时候我们需要再对象外面再包一个括号
        var sum = (num1, num2) => { return num1 + num2; }
        
        // 1 返回对象
        let getTempItem = id => { id: id, name: "Temp" };
        // 2 Unexpected token :
        let getTempItem = id => ({ id: id, name: "Temp" });
        
        // 结合解构
        const full = ({ first, last }) => first + ' ' + last;
        
        // rest
        const numbers = (...nums) => nums;
        numbers(1, 2, 3, 4, 5);
        // [1,2,3,4,5] 
    

    箭头函数使用的注意点:

    • 函数体内的this对象指向定义时所在的对象而不是使用时所在的对象
         function week() {
             setTimeout(() => {
                 console.log('id:', this.id);
             }, 100);
         }
         //定义全局id(使用时的所在id)
         var id = 21;
         //调用,改变了this的值
         week.call({ id: 42 });
         // 42
         
         function week() {
             return () => {
                 return () => {
                     return () => {
                         console.log('id:', this.id);
                     };
                 };
             };
         }
         //定义时的id=1,决定了它的作用域,因此下面的t1,t2,t3的输出结果均为1
         var f = week.call({id: 1});
         
         var t1 = f.call({id: 2})()();
         var t2 = f().call({id: 3})();
         var t3 = f()().call({id: 4});
         // 1 
         
         // 对象不构成作用域 
         const cat = {
             lives: 9,
             jumps: () => {
                 this.lives--;
             }
         }
      
    • 不可以当作构造函数,因为定义的时候是全局的
    • 不可以使用argument对象,这是一个规定,需要使用rest来代替
    • 不可以使用yield命令

    6:尾调用

    一般用于严格模式,也就是说在严格模式下面,ES6做了一个尾调用的优化;但是在非严格模式下虽然也可以使用尾调用,但是没有优化。

    尾调用基本概念:最后一步是调用另一个函数,不适用于外部变量时只保留内层函数的调用帧(外部的变量不应该保存在return这个函数里面,也就是返回的return并不使用这个作用域)。

    function f(x){
        return g(x);
    }
    

    7:尾递归(会有一个调用栈的堆积)

        function factorial(n) {
            if (n === 1) return 1;
            return n * factorial(n - 1);
        }
        
        factorial(5);
        
        // 尾递归
        function factorial(n, total) {
            if (n === 1) return total;
            return factorial(n - 1, n * total);
        }
        
        factorial(5, 1)
    

    8:函数参数的尾逗号,方便代码版本管理

        func(
            'week',
            'month',
        );
    

    相关文章

      网友评论

        本文标题:函数的扩展

        本文链接:https://www.haomeiwen.com/subject/hntvjctx.html