前面的文章中,我在介绍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);
}
};

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

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

Javascript高级编程学习笔记(23)—— 函数表达式(1)递归的更多相关文章

  1. Javascript高级编程学习笔记(25)—— 函数表达式(3)模仿块级作用域

    昨天写了闭包 今天就来聊聊块级作用域的事情 在绝大多数编程语言中,都有块级作用域这个概念 什么是块级作用域呢? 前面我们在刚开始讲的时候说过,JS中的大括号(不在赋值运算符的后面)表示代码块 块级作用 ...

  2. Javascript高级编程学习笔记(26)—— 函数表达式(4)私有变量

    私有变量 严格来讲,JS中没有私有成员的概念,所有对象属性都是公有的. 但是JS中有私有变量的概念 所有在函数中定义的变量都可以认为是私有变量,因为不能在函数外部进行访问 私有变量包括 1.函数参数 ...

  3. Javascript高级编程学习笔记(24)—— 函数表达式(2)闭包

    昨天的文章中主要记录了,函数表达式与函数声明的区别 以及在JS中如何安全地使用递归 那么既然要深入地理解JS中的函数,闭包就是一个绕不开的概念 闭包 JS高编一书中对闭包的概念定义如下: 闭包是指有权 ...

  4. 《JavaScript高级程序设计》笔记:函数表达式(七)

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

  5. Javascript高级编程学习笔记(16)—— 引用类型(5) Function类型

    JS中许多有趣的地方都和函数脱不了联系 那么是什么让JS中的函数这么有趣呢? 我们一起来看看吧 Function类型 在JS中函数实际上就是对象,每个函数都是Function类型的实例,和JS的其他引 ...

  6. Javascript高级编程学习笔记(7)—— 函数

    前几天有事耽搁了,今天继续更新 今天的主要内容是JS中的函数 这一篇主要讲函数的定义等内容,至于变量提升.执行环境.闭包.内存回收等内容在后面讲,高玩们可以不用看下面的正文了. 函数 首先来讲,函数对 ...

  7. JavaScript高级编程学习笔记(第三章之一)

    继续记笔记,JavaScript越来越有意思了. 继续... 第三章:JavaScript基础 ECMAScript语法在很大程度上借鉴了C和其它类似于C的语言,比如Java和Perl. 大小写敏感: ...

  8. Javascript高级编程学习笔记(6)—— 流程控制语句

    话不多说,我们直接开始进入今天的主题 流程控制语句 首先什么是流程控制语句呢? 顾名思义,就是控制流程的语句. 在JS中语句定义了ECMAScript中的主要语法,让我们可以使用一系列的关键字来完成指 ...

  9. Javascript高级编程学习笔记(3)—— JS中的数据类型(1)

    前一段时间由于事情比较多,所以笔记耽搁了一段时间,从这一篇开始我会尽快写完这个系列. 文章中有什么不足之处,还望各位大佬指出. JS中的数据类型 上一篇中我写了有关JS引入的Script标签相关的东西 ...

随机推荐

  1. git GUI设置长期记住密码

    git config --global credential.helper store

  2. ROS零门槛学渣教程系列(一)——ubuntu安装

    本教程使用虚拟机安装ubuntu 实验前准备:下载ubuntu系统镜像 本教程使用的是ubuntu14.04lts版本,有能力的读者可自行下载安装. 推荐使用本人制作的镜像,该镜像已安装好ROS.和配 ...

  3. 对DOM,SAX,JDOM,DOM4J四种方法解析XML文件的分析

    1.DOM 与平台无关的官方解析方式 DOM是一次性把xml文件加载到内存中,形成一个节点树 对内存有要求 2.SAX java提供的基于事件驱动的解析方式 每次遇到一个标签,会触发相应的事件方法 3 ...

  4. qt布局管理-缩放、多窗口切换

    关于缩放的布局 所有控件要求与主窗口同时缩放,那么在所有控件设置好布局后,最后点击最外侧的主控件,选择水平布局或者垂直布局即可. 另外每个空间的属性可更改,如SizePolicy用于设置空间是否可缩放 ...

  5. 常用jquery

    水果:<input type="checkbox" name="shuiGuo" value="2">苹果<input t ...

  6. mysql 1055

    在 /etc/my.cnf 文件里加上如下: sql_mode=NO_ENGINE_SUBSTITUTION

  7. 详解js跨域

    什么是跨域? 概念:只要协议.域名.端口有任何一个不同,都被当作是不同的域. 对于端口和协议的不同,只能通过后台来解决.URL 说明 是否允许通信 http://www.a.com/a.js http ...

  8. AndroidStudio 问题点 - app:preFUNDebugAndroidTestBuild

    Error:Execution failed for task ':app:preFUNDebugAndroidTestBuild'. >Conflictwith dependency 'com ...

  9. 20155312 张竞予 Exp9 Web安全基础

    Exp9 Web安全基础 目录 基础问题回答 (1)SQL注入攻击原理,如何防御 (2)XSS攻击的原理,如何防御 (3)CSRF攻击原理,如何防御 实践过程记录 WebGoat准备工作 1.XSS攻 ...

  10. 4月23日 db 命令操作 和表操作

    1内容回顾: # 补充的知识点 # server端肯定是确定下来的 # mysql的客户端 # mysql.exe 直接在命令行就可以运行的 (学习阶段用) # navicat等可视化的客户端,是第三 ...