闭包与即时函数

有一个重要的构造是在 JavaScript 高级函数式编程中经常使用的,这种构造依赖于对闭包的充分利用,比如:(function(){})()
这种模式的代码,毫无疑问可能用在很多地方,它给 JavaScript 语言带来了出乎意料的能力。让我们分解这段代码,探究其内部到底发生了什么。

首先,先忽略第一组括号的内容,再回头来看代码:(...)()

众所周知,可以通过函数名加圆括号:functionName(),的语法方式调用任意一个函数。但是在这里,我们可以使用任意一个引用函数实例的表达式作为函数的名称。就像下面的代码,使用变量名调用该变量所引用的函数:

与其它表达式在一起使用,我们需要将一个操作符——函数调用操作符 ( ) ,应用在整个表达式上,所以需要用圆括号将该表达式括起来。

也就是说,在 (...)() 中,第一组圆括号仅仅是用于划定表达式的范围,而第二个圆括号则是一个操作符。如下代码,将函数引用通过圆括号括起来是完全合法的:

查看全文

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

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

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

查看全文

闭包是如何工作的?

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

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

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

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

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

查看全文

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

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

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

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

查看全文

JavaScript 的作用域链浅析

JavaScript 是基于词法作用域的语言:通过阅读包含变量定义在内的数行源代码就能知道变量的作用域。

一些类 C 的语言是使用块级作用域(block scope),花括号内的第一段代码都具有各自的作用域,而且变量在声明它们的代码之外是不可见的。

而 JavaScript 中没有块级作用域,取而代之地使用了函数作用域(function scope),即词法作用域:变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义。词法作用域意味着变量在声明之前甚至已经可用,JavaScript的这个特性被非正式地称为声明提前(hoisting),如下代码:

继续阅读