函数的递归调用

递归(recursion)是经常遇到的一个概念。当函数调用自身,或调用另外一个函数,但这个函数的调用树中的某个地方又调用了自己时,递归就发生了。

对任何类型的程序来说,递归都是一个非常有用的技术——很多数学公式在本质上都是递归。而且,对树进行遍历时,递归也是非常有用的,这是一个可能会在 Web 程序中出现的构造。我们还可以使用递归深入理解函数在 JavaScript 中是如何工作的。

从最简单的开始。

普通命名函数中的递归

有很多常见的递归函数示例。其中一个是用于检测回文——相当于递归技术的“Hello World”。

回文的非递归定义是“一个短语,不管从哪个方向读都是相同的”,我们可以用它来实现一个函数,用于创建反向字符串并和字符串本身进行比较。但是复制字符串从多方面来产不是简洁的解决方案,其中一个原因就是需要分配并创建新的字符串。

通过利用回文的更多数学定义,我们要可以想出一个更简洁的解决方案,这些定义如下所示:

  1. 单个与零个字符都是一个回文。
  2. 如果字符串的第一个字符和最后一个字符相同。将这前后两个排除后,其它的字符串仍是一个回文的话,我们称原字符串是一个回文。

查看全文

使用闭包实现缓存记忆(memoization)

缓存记忆让函数能够记录它之前被调用时所产生的结果。这样,我们第二次获取结果值时,优先从函数的缓存记录中查找结果,避免重复计算结果。

首先要实例一个无闭包的版本:

查看全文

闭包是如何工作的?

简单来说,闭包(closure)是函数在声明时访问函数自身之外的变量时所创建的作用域

让我们将这句话分解来看:一、闭包是作用域,二、函数在声明时访问外部变量所创建的作用域。另外:声明的函数在后续的任何时刻都可以被调用,即使是声明时的作用域消失之后。

从最简单的代码开始理解:

在这个最简单的例子中,outerFunction能够访问到外部的outerValue变量。这样的代码,我们可能已经编写了成千上万次,但是却没有意识到其实我们已经创建了一个闭包。

一点都不特别是吧?因为外部变量与外部函数都是在全局作用域内声明的,该作用域(也是闭包)从未消失过(因为页面已经被加载)。所以该函数可以访问到外部变量也就不足为奇了,因为它仍在作用域内并且是可用的。这种情况下,即使有闭包的存在,我们也不清楚他的好处。

查看全文

利用参数个数以及闭包进行函数重载

基于传入的参数,有很多种方法可以判断并进行函数重载。一种通用的方法是,根据传入参数的类型执行不同的操作;另一种方法是,可以通过判断某些特定的参数是否存在来执行不同的操作;还有一种方法是判断传入参数的个数来执行不同的操作。本文介绍的就是最后一种方法。

对于一个函数,在参数方面,我们可以确定两件事情:

  • 通过函数的length属性,可以知道声明了多少命名参数(形参个数)
  • 通过arguments.length,可以知道在调用时传入了多少参数(实参个数)

查看全文

函数的四种调用方式

一共有四个不同的方式可以进行函数调用,每种方式都有自己的细微差别。

  • 作为一个函数进行调用,是最简单的形式
  • 作为一个方法在对象上进行调用,支持面向对象编程
  • 作为构造器进行调用,创建一个新对象
  • 通过apply()call()方法进行调用

除了最后一种方式,其他方法的函数的调用,都是通过在表达式后面加上小括号来执行函数引用。如果给函数传递参数,则需要将参数放在小括号里并以逗号分隔:expression(arg1,arg2)

查看全文