zoukankan      html  css  js  c++  java
  • Javascript高级编程学习笔记(23)—— 函数表达式(1)递归

    前面的文章中,我在介绍JS中引用类型的时候提过,JS中函数有两种定义方式

    第一种是声明函数,即使用function关键字来声明

    第二种就是使用函数表达式,将函数以表达式的形式赋值给一个变量,这个变量就保存了对这个函数的引用

    function与表达式的区别前文也已经详细分析过,这里就大概讲解一下

    虽然两者在写法上没有什么不同,但是function关键字作为函数声明的时候,与var一样会有变量提升的效果

    其本质是在JS创建执行环境的时候,就完成了对函数的声明,所以访问该函数的代码在函数声明语句前就可以使用

    但是函数表达式不一样,在JS中 = 后面的内容会被归为表达式上下文,而这种上下文中 function 关键字并没有变量提升的特权

    因为,这段表达式的代码,会在执行上下文创建完成后才,会被执行

    函数表达式定义函数

    var a = function(){
        // 代码块
    }

    上面这种定义函数的方式,也是我们最常用的函数表达式的定义方式

    我们在这种情况下没必要给函数一个名字,因为已经有一个变量保存了对该函数的引用。

    和函数名的作用一样,所以没必要重复创建

    PS.这种没有标识符的函数叫匿名函数,也叫拉姆达函数,函数的name属性为空字符串

    在流程控制语句中使用函数表达式

    可能许多小伙伴听过一个说法,那就是不要在 if for while 中声明函数

    这是为什么呢?

    首先我们应该明确,这里指的声明是指使用 function 关键字进行函数声明,而不是使用函数表达式

    不让大家在流程控制语句中进行函数声明的主要原因就是,这种写法虽然在逻辑上没有问题,但是在JS解析时会出现错误

    我们刚才说过,使用function 关键字声明的函数会有个变量提升的过程

    在创建执行上下文的时候,函数的定义就已经完成了

    那么问题来了

    流程控制语句在代码执行时才会进行判断,而你的声明在判断之前就已经完成了

    所以在大部分浏览器中你的流程控制语句并不会有任何作用

    但在小部分浏览器,比如火狐针对这一问题是可以按照逻辑完成声明的

    所以我们不应该在流程控制语句中进行函数声明

    但是话又说回来,万一我就是要在流程控制语句中按照情况来定义函数呢?

    那么函数表达式就是你的理想选择

    因为不让用的原因就是 function 的变量提升,而函数表达式又不会变量提升,当然就可以安全地使用了

    除此而外,当我们需要将函数作为值传递的时候,函数表达式依然是你的首选(避免一些奇奇怪怪的错误)

    递归

    我的这系列文章,主要是记录自己在学习JS中的一些知识点

    所以并不会在这里讲递归算法

    主要是说一下递归中存在的问题

    抛开ES6中的尾调用优化不谈

    在ES5中,我们平时习以为常的递归写法很可能存在一些隐患

    function factorial(num){
        if(num <= 1){
            return 1;
        }else{
            return num * factorial(num-1);
        }
    }

    上方是一个经典的阶乘递归函数

    小伙伴们觉得有啥问题么?

    没看出来,没关系

    看看下面的代码

    var anotherFactorial = factorial;
    factorial = null;
    anohterFactorial(5); // 报错

    我先用一个变量来保存对这个递归函数的引用

    然后去掉它原本的引用

    但我通过新的引用执行函数时,js报错了

    为啥?

    因为我们的递归使用的是原来的引用来进行递归调用的

    而我们已经切断了原来的引用,所以函数执行时报错

    换句话说,这种递归函数的写法耦合度较高

    那么怎么解决呢?

    function factorial(num){
        if(num <= 1){
            return 1;
        }else{
            return num * arguments.callee(num-1);
        }
    }

    之前我们说过,arguments有个callee属性指向函数本身

    这里用这种方法就可以解决之前的问题

    但是这种方法还有一个问题,在严格模式下不可用

    怎么办呢?

    var factorial = function f(num){
        if(num <= 1){
            return 1;
        }else{
            return num * f(num-1);
        }
    };

    当然是使用函数表达式啦,这种方式在严格模式下依然可用

    以上就是函数表达式关于递归的内容啦,明天更闭包的内容,不见不散

  • 相关阅读:
    记录C#开发遇到的问题和应用经验
    HttpApplication,HttpModule,HttpContext及Asp.Net页生命周期
    itextsharp.dll(4.0.8.0)完整示例PDF
    步步为营 .NET 设计模式学习笔记 二十三、Interpreter(解释器模式)
    .net简谈分层架构思想
    FusionCharts Free
    表解锁的方法
    步步为营 .NET 设计模式学习笔记 二十一、Visitor(访问者模式)
    步步为营 .NET 设计模式学习笔记 二十二、Memento(备望录模式)
    再论抽象
  • 原文地址:https://www.cnblogs.com/lhyxq/p/10177585.html
Copyright © 2011-2022 走看看