JavaScript 学习笔记6

第七章 函数表达式程序员

定义函数:a.函数声明function functionName(name,age){}————函数声明提高面试

                     b.函数表达式 var functionName=function(name,age){};闭包

递归函数

闭包性能

变量的做用域无非就是两种:全局变量和局部变量。spa

Javascript语言的特殊之处,就在于函数内部能够直接读取全局变量。指针

如何从外部读取局部变量?对象

那就是在函数的内部,再定义一个函数。把内部函数做为返回值,就能够从外部读取它的内部变量了递归

闭包就是可以读取其余函数内部变量的函数。索引

因为在Javascript语言中,只有函数内部的子函数才能读取局部变量,所以能够把闭包简单理解成“定义在一个函数内部的函数”。

因此,在本质上,闭包就是将函数内部和函数外部链接起来的一座桥梁。

它的最大用处有两个,一个是前面提到的能够读取函数内部的变量,另外一个就是让这些变量的值始终保持在内存中。

 

使用闭包的注意点

1)因为闭包会使得函数中的变量都被保存在内存中,内存消耗很大,因此不能滥用闭包,不然会形成网页的性能问题,在IE中可能致使内存泄露。解决方法是,在退出函数以前,将不使用的局部变量所有删除。

2)闭包会在父函数外部,改变父函数内部变量的值。因此,若是你把父函数看成对象(object)使用,把闭包看成它的公用方法(Public Method),把内部变量看成它的私有属性(private value),这时必定要当心,不要随便改变父函数内部变量的值。

 

闭包是一个比较抽象的概念,尤为是对js新手来讲.书上的解释实在是比较晦涩,对我来讲也是同样.

  可是他也是js能力提高中没法绕过的一环,几乎每次面试必问的问题,由于在回答的时候.你的答案的深度,对术语的理解以及js内部解释器的运做方式的描述,都是能够看出你js实际水平的.即便你没答对,也能让考官对你的水平有个评估.那么我先来讲说我对js中的闭包的理解.

  闭包是不少语言都具有的特性,在js中,闭包主要涉及到js的几个其余的特性:做用域链,垃圾(内存)回收机制,函数嵌套,等等.

  在理解闭包之前.最好能先理解一下做用域链的含义,简单来讲,做用域链就是函数在定义的时候建立的,用于寻找使用到的变量的值的一个索引,而他内部的规则是,把函数自身的本地变量放在最前面,把自身的父级函数中的变量放在其次,把再高一级函数中的变量放在更后面,以此类推直至全局对象为止.当函数中须要查询一个变量的值的时候,js解释器会去做用域链去查找,从最前面的本地变量中先找,若是没有找到对应的变量,则到下一级的链上找,一旦找到了变量,则再也不继续.若是找到最后也没找到须要的变量,则解释器返回undefined.

  了解了做用域链,咱们再来看看js的内存回收机制,通常来讲,一个函数在执行开始的时候,会给其中定义的变量划份内存空间保存,以备后面的语句所用,等到函数执行完毕返回了,这些变量就被认为是无用的了.对应的内存空间也就被回收了.下次再执行此函数的时候,全部的变量又回到最初的状态,从新赋值使用.可是若是这个函数内部又嵌套了另外一个函数,而这个函数是有可能在外部被调用到的.而且这个内部函数又使用了外部函数的某些变量的话.这种内存回收机制就会出现问题.若是在外部函数返回后,又直接调用了内部函数,那么内部函数就没法读取到他所须要的外部函数中变量的值了.因此js解释器在遇到函数定义的时候,会自动把函数和他可能使用的变量(包括本地变量和父级和祖先级函数的变量(自由变量))一块儿保存起来.也就是构建一个闭包,这些变量将不会被内存回收器所回收,只有当内部的函数不可能被调用之后(例如被删除了,或者没有了指针),才会销毁这个闭包,而没有任何一个闭包引用的变量才会被下一次内存回收启动时所回收.

也就是说,有了闭包,嵌套的函数结构才能够运做,这也是符合咱们的预期的.而后,闭包还有一些特性,却每每让程序员以为很难理解.

看看下面一段代码.

 

var result=[];function foo(){

    var i= 0;

    for (;i<3;i=i+1){

        result[i]=function(){

            alert(i)

        }

    }

};

foo();

result[0](); // 3

result[1](); // 3

result[2](); // 3

 

这段代码中,程序员但愿foo函数中的变量i被内部循环的函数使用,而且能分别得到他们的索引,而实际上,只能得到该变量最后保留的值,也就是说.闭包中所记录的自由变量,只是对这个变量的一个引用,而非变量的值,当这个变量被改变了,闭包里获取到的变量值,也会被改变.

解决的方法之一,是让内部函数在循环建立的时候当即执行,而且捕捉当前的索引值,而后记录在本身的一个本地变量里.而后利用返回函数的方法,重写内部函数,让下一次调用的时候,返回本地变量的值,改进后的代码

var result=[];function foo(){

    var i= 0;

    for (;i<3;i=i+1){

        result[i]=(function(j){

            return function(){

                alert(j);

            };

        })(i);

    }

};

foo();

result[0](); // 0

result[1](); // 1

result[2](); // 2

 

在这里我再解释一下.这里用到了另外2个技术,当即调用的匿名函数和返回函数.也是初学者比较难以理解的部分.

私有变量

任何在函数中定义的变量,均可以是私有变量。

把有权访问私有变量和私有函数的方法称为特权方法,a)在构造函数中定义特权方法

b)在私有做用域中定义变量或函数,私有变量和函数由实例共享

模块模式——为单例建立私有变量和特权方法。单例,指只有一个实例的对象

使用一个返回对象的匿名函数,函数内部首先定义私有变量和函数,将一个对象字面量做为函数的值返回,返回的 对象字面量只包含公开的属性和方法。

相关文章
相关标签/搜索