• 函数表达式的特征
  • 使用函数实现递归
  • 使用闭包定义私有变量
前面我们说到定义函数有两种方式:函数声明、函数表达式。
两者的区别在于函数声明提升,前者在执行之前的上下文环境中直接被赋值,而后者不会。
一、递归
递归函数是一个函数通过名字调用自身的情况下构成的。
     function factorial(num){
         if(num<1){
             return 1;
         }else{
             return num * arguments.callee(num-1);
         }
     }

alert(factorial(10));

二、闭包
闭包的核心概念就是指有权访问另一个函数作用域中变量的函数。
创建闭包的常见方式主要就是在一个函数内部创建另一个函数。
     function createCompareFunction(proprtyName){
         return function(obj1,obj2){
             if(obj1[proprtyName]>obj2[proprtyName]){
                 return 1;    
             }else if(obj1[proprtyName]<obj2[proprtyName]){
                 return -1;
             }else{
                 return 0;
             }
         }
     }
     var o1 = {name : 'zjh'};
     var o2 = {name : 'azz'};
     var f = createCompareFunction('name');

alert(f(o2,o1)); //-1

内部匿名函数中调用的proprtyName就是另一个函数作用域中的变量。当f被赋值后,外层函数的作用域链被销毁,但是他的活动对象仍然在内存中,因为它的活动对象被返回的匿名函数引用了。
所以闭包会占用很多内存,要在必要的时候使用。
2.1闭包与变量
作用域链的这种机制也会有一定的副作用:
     function createFunction(){
         var array = new Array();
         for(var i = 0 ; i < 10 ; i++){
             array[i] = function(){
                 return i;
             }
         }
          i = 20;
         return array;
     }
     var a = createFunction();

alert(a[6]())//20  

应该是6,这是却是20。原因就是数组中的每一项都是function(){return i},而此时的i的值是createFunction执行完的20。
     function createFunction(){
         var array = new Array();
         for(var i = 0 ; i < 10 ; i++){
             array[i] = function(num){
                 return num;
             }(i)
         }
          i = 20;
         return array;
     }
     var a = createFunction();

alert(a[6])//20  

利用了函数参数按值传递的特性。
2.2关于this对象
this对象时在运行时基于函数执行环境绑定的。在全局函数中,this等于window,而当函数作为某个对象的方法调用时,this等该对象。
匿名函数执行环境具有全局性。因此this通常指向window。
     var k = 'window';
     var o = {
         k : 'object',
         getName : function(){
             return function(){
                 return this.k;
             }
         }
     }

alert(o.getName()())  

2.3内存泄漏
在IE浏览器中,因为dom对象和js对象存在浏览器的不同地方,如果闭包的作用域链中保存着一个HTML元素,那么该元素就无法被销毁。
function createF(){
    var ele = document.getElementById('aa');
    ele.onclick = function(){
        alert(ele.value);
    }

}

避免泄漏:
function createF(){
    var ele = document.getElementById('aa');
    var k = ele.value;
    ele.onclick = function(){
        alert(k);
    }
    ele = null;

}

三、模仿块级作用域
JS中没有块级作用域,如果要使用需要在函数中定义来模仿。
(function(){
    for(var i =0 ; i<10 ; i++){
        var k = 10;
    }
})()

alert(i) //错误  

因为i在块级作用域执行完后 就销毁了。
只要临时需要一些变量,可以使用私有作用域。这种技术经常用在全局作用域中的外部函数,可以限制向全局作用域中添加过多的变量和函数。
也能有效的减少闭包占用内存的问题。因为没有指向匿名函数的引用,只要函数执行完毕,就可以立即销毁其作用域了。
四、私有变量
JS中没有私有成员的概念,所以属性都是公有的,但是有一个私有概念,那就是在任何函数中定义的变量,都可以认为是私有变量,因为不能在函数外部访问这些变量。
这些私有变量包括:函数的参数,局部变量,函数内部定义的其它函数。
function add(num1,num2){
    var a = '1500';

}  

在这个函数中,有三个私有变量,num1,num2,a。我们可以在函数内部访问他们,或者通过函数内部的闭包通过作用域来访问他们。那么我们利用这一点就可以创建用于访问私有变量的特权方法
有两种方式可以创建特权方法:
4.1私有变量
第一种:利用闭包
function Person(name){
    this.setName = function(value){
        name = value;
    }
    this.getName = function(){
        return name;
    }
}
var p = new Person();
p.setName('zjh');

alert(p.getName());

所以,利用私有成员和特权成员可以隐藏那些不该被直接修改的数据。
缺点:是必须使用构造函数模式来达到这个目的。前面提到过,构造函数模式的缺点是:每次实例化一个对象,都会创建一组同样的新方法。
4.2静态私有变量
在私有作用域中定义私有变量或者函数,也可以创建特权方法。
    var privateVariable = 10;
    function privateFuntion(){
        return false;
    }
    MyObject = function(){};
    MyObject.prototype.publicMethod = function(){
        privateVariable++;
        return privateFuntion();
    }
    var o = new  MyObject();

alert(o.publicMethod());  

这个模式在定义构造函数时没有使用函数声明,而是使用了函数表达式。函数表达式只能创建局部函数,所以我们不使用关键字var 来定义了MyObject ,未经过初始化声明的变量总是会创建一个全局变量。(在严格模式下会错误)
这个模式与在构造函数中定义特权方法的区别在于:私有变量和函数是→实例共享的,由于特权方法是在原型上定义的,因此所有实例都使用同一个函数。而这个特权方法作为一个闭包,总是保存着对包含作用域的引用。
(function(){
    var name = '';
    Person = function(value){
        name = value;
    }
    Person.prototype.setName = function(value){
        name = value;
    }
    Person.prototype.getName = function(){
        return name;
    }
})()
var p = new Person('zjh');
alert(p.getName());//zjh
var pp = new Person('zzz');
alert(pp.getName());//zzz

alert(p.getName());//zzz

可见这种方式创建的是静态私有变量。
4.3模块模式
之前的模式是为自定义类型添加私有变量。而这种模块模式是为单例模式的对象添加私有属性。
方法如下:
var singleton = function(){
    var privateVar = 10;
    function privateFun(){
        return false;
    }
    return {
        publicVar : true,
        publicMethod : function(){
            privateVar++;
            return privateFun();
        }
    }
}()

alert(singleton.publicMethod());

如果必须创建一个对象并以某些数据对其进行初始化,同时还要公开一些能够访问这些私有数据的方法,那么就可以用到这种模块方式。
4.3增强的模块模式
function Person(){}
var singleton = function(){
    var privateVar = 10;
    function privateFun(){
        return false;
    }
    var o = new Person();
    o.publicVar = true;
    o.publicMethod = function(){
        privateVar++;
        return privateFun();
    }    
    return o;
}()

alert(singleton.publicMethod());  

这种模式 在匿名函数中创建了一个指定类型的对象,用来返回。
五、小结
在JS中,函数表达式是一种非常有用的技术。使用函数表达式无须命名,从而实现动态编程。
特点:
函数表达式不一定有名字,没有名字的函数表达式叫做匿名函数。
在无法确定如何引用函数的情况下,递归函数变得比较复杂。
递归函数中应该用arguments.callee来递归自身,以防止函数名变化。
 
当在函数内部定义其他函数时就创建了闭包。闭包有权访问 包含函数 的 内部的所有变量,原理:
在后台执行环境中,闭包的作用域链包含它自身的作用域、包含函数的作用域、全局作用域。
通常,函数的作用域及其变量都会在函数执行结束了被销毁。
但是,当函数返回一个闭包时,这个函数的作用域会在内存中一直保存到闭包不存在为止。
 
使用闭包可以在对象中创建私有变量:
可以使用构造函数模式、原型模式、来实现自定义类型的特权方法;也可以使用模块模式、增强模式的模块模式来实现单利的特权方法。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

JavaScript高级 函数表达式 《JavaScript高级程序设计(第三版)》的更多相关文章

  1. JavaScript高级程序设计第三版.CHM【带实例】

    从驱动全球商业.贸易及管理领域不计其数的复杂应用程序的角度来看,说 JavaScript 已经成为当今世界上最流行的编程语言一点儿都不为过. JavaScript 是一种非常松散的面向对象语言,也是 ...

  2. 22.1 高级函数【JavaScript高级程序设计第三版】

    函数是JavaScript 中最有趣的部分之一.它们本质上是十分简单和过程化的,但也可以是非常复杂和动态的.一些额外的功能可以通过使用闭包来实现.此外,由于所有的函数都是对象,所以使用函数指针非常简单 ...

  3. javascript高级程序设计第三版书摘

    在HTML 中使用JavaScript <script>元素 在使用<script>元素嵌入 JavaScript 代码时,只须为<script>指定 type 属 ...

  4. JavaScript Function(函数表达式)

    创建函数 创建函数的方式有两种:1.函数声明,2.函数表达式 函数声明的语法为 functionName(); //不会报错,函数声明提升function functionName(arg0,arg1 ...

  5. 谈谈javascript的函数表达式及其应用

    我们都知道定义函数的方式有两种,一种是函数声明,另外一种就是函数表达式. 函数声明 语法为:function关键字后跟函数名.例如: function functionName(arg0) { //函 ...

  6. 【JavaScript】函数表达式

    一.前言        接着上一篇的内容,继续学习JavaScript. 二.内容       函数的声明 function functionName(arg0,arg1,arg2){ //函数体 } ...

  7. 浅谈JavaScript的函数表达式(闭包)

    前文已经简单的介绍了函数的闭包.函数的闭包就是有权访问另一个函数作用域的函数,也就是函数内部又定义了一个函数. var Super=function(num){ var count=num; retu ...

  8. 浅谈JavaScript的函数表达式(递归)

    递归函数,在前面的博客中已经简单的介绍了.递归函数是一个通过函数名称在函数内部调用自身的函数.如下: function fac(num){ if(num<1){ return 1; } else ...

  9. javascript中函数表达式的问题讨论

    #函数表达式 ##函数声明和函数表达式的区别 函数的定义有两种形式,一种是函数声明,一种是函数表达式 使用声明时,要注意函数声明提升现象,比如说在if语句中使用声明会出错,但是表达式就不存在这个问题 ...

随机推荐

  1. Web性能压力测试工具之ApacheBench(ab)详解

    PS:网站性能压力测试是性能调优过程中必不可少的一环.只有让服务器处在高压情况下才能真正体现出各种设置所暴露的问题.Apache中有个自带的,名为ab的程序,可以对Apache或其它类型的服务器进行网 ...

  2. 和为S的两个数字VS和为s的连续正数序列

    题目:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s.如果有多对数字的和等于s,输出任意一对即可. 例如输入数组1.2.4.7.11.15和数字15.由于4+11=15, ...

  3. .nil? .empty? .blank? .present? in Ruby on Rails

    We get confused when there are many options to choose from. Same is the case when it comes to use an ...

  4. Jmeter Html 报告优化

    转载自南风_real博客园:http://www.cnblogs.com/jaychang/p/5881525.html 但是最近在查阅相关资料时,发现基本都是重复一篇文章Jmeter使用笔记之htm ...

  5. [ActionScript 3.0] AS3.0 本机鼠标指针

    Flash Player 10.2添加了内置的本机鼠标指针(native mouse cursor)支持,虽然在之前的版本里我们可以侦听MouseEvent事件来模拟鼠标指针,但是在有了原生的本机鼠标 ...

  6. linux 可用内存查看

    用free命令查看. 下面是一个例子(单位是MB): [root@linuxzgf ~]# free -m total used free shared buffers cachedMem: 7982 ...

  7. 前端之JavaScript

    JavaScript JavaScript 是一种轻量级的编程语言:是可插入 HTML 页面的编程代码:JavaScript 插入 HTML 页面后,可由所有的现代浏览器执行. 一,编写方式 1.Ja ...

  8. PL/SQL Developer使用技巧、快捷键

    1.类SQL PLUS窗口:File->New->Command Window,这个类似于oracle的客户端工具sql plus,但比它好用多了. 2.设置关键字自动大写:Tools-& ...

  9. OC基础(15)

    @property参数 @Property练习 @class 循环retian *:first-child { margin-top: 0 !important; } body > *:last ...

  10. Redis多机功能介绍

    Redis多机功能目的:以单台Redis服务器过渡到多台Redis服务器 Redis单机在生产环境中存在的问题 1.内存容量不足 Redis使用内存来存书数据库中的数据,但是对于一台机器来说,硬件的内 ...