JavaScript函数表达式——“函数的递归和闭包”的注意要点

  • A+
所属分类:JavaScript

JavaScript函数表达式——“函数的递归和闭包”的注意要点

函数表达式的基本概念

name属性和函数提升

首先,name属性,通过这个属性可以访问到给函数指定的名字。(非标准的属性)如:

其次,函数声明提升,意味着可以把函数声明放在调用它的语句后面。如:

使用函数表达式则不可以:

创建函数的两种方式,一个是函数声明(如第一种方式);一个是函数表达式(如第二种方式)。第二种函数创建方式创建的函数叫“匿名函数”或“拉姆达函数”,因为function 关键字后面没有标识符。

函数提升的常见错误

需要注意的是,作为对比,下面的两种代码中,第一个是错误的(会导致各浏览器出现不同的问题);第二个才使正确的。代码如下:

报错

没有错误

这里也不会出现问题。出现上面问题的根源就是函数提升,就是函数声明和函数表达式之间的区别所导致的。

函数的递归

递归函数就是在一个函数通过名字调用自身的情况下构成的。如:

但是,函数里面包含了函数自身所以,在应该使用arguments.callee来解决该问题。如:

但如果使用上面这种方法,则在严格模式下行不通。不过可以使用命名函数表达式来达成相同的结果。如:

即,把它包含在一个变量里面,在遇到其他这种需要使用arguments.callee的时候都可以这样做。

函数的闭包

闭包就是有权访问另一个函数作用域中的变量的函数。常见的创建闭包的方式就是在一个函数内部创建另一个函数。在此之前应该先掌握作用域链的概念(见《Javascript执行环境和作用域的注意要点》一文《Javascript执行环境和作用域的注意要点》

作用域链

以下面的代码为例

调用函数compare时,函数执行环境中的作用域链:JavaScript函数表达式——“函数的递归和闭包”的注意要点

作用域链本质上是一个指向变量对象的指针列表。

另一个例子:

这个就相当于:

相当于:

所以,完整的代码如下:

调用compareNames()函数的过程中产生的作用域链之间的关系图如下:JavaScript函数表达式——“函数的递归和闭包”的注意要点

常见的闭包的模式一般都是这样:

举个栗子:

闭包会携带他包含的函数的作用域,因此会更多的占用内存资源,建议只有在绝对必要的时候再考虑使用闭包。V8 优化后的js 引擎会尝试收回被闭包占用的内存。

闭包与变量

闭包的副作用是闭包只能取得包含函数中任何变量的最后一个值。

this对象

全局函数中this = window;当函作为位某个对象的方法调用时this = 那个对象;但是匿名函数的执行环境又全局性,this 通常指向window;但也有例外:

因为每个函数在被调用的时候都会自动取得两个特殊的变量:this 和arguments;内部函数在搜索这两个变量时,只会搜索到其活动对象为止。

上面这个代码就是因为闭包的问题,导致错误。又如:

解决这个问题的方法是:

又如:

再举个栗子:

另外,在几种特殊情况下,this 的值可能会发生改变。如:

只要不用下面两种方式调用函数即可。

内存泄露

经过上面的一番折腾,最明显的就是window.name 一直占用内存,无法清空。必须手动把它清理掉,用window.name = null来操作。

weinxin
我的微信公众号
我的微信公众号扫一扫

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: