函数定义

定义函数方法有两种:声明式表达式

1.声明式(普通形),略

2.表达式(赋值形)

匿名函数(anonymous function)、有时候也叫拉姆达函数。存在函数声明提升问题、闭包this指针问题
函数声明提升问题(function declaration hoisting): 声明式放在哪里都没问题。但是如果是表达式的函数,调用时不能放在定义之后的!

sayHi();    //错误:函数还不存在 
var sayHi = function(){ 
    alert("Hi!"); 
}; 

递归(带名字的lambda函数实现)

arguments.callee是当前执行函数的指针,但是在严格模式下不允许访问。所以通过带名字的lambda函数实现

var factorial = (function f(num){ 
    if (num <= 1){  
        return 1; 
    } else { 
        return num * f(num-1); 
    } 
}); 

闭包 (解决GC回收内存释放、块级作用域等问题)

闭包是指有权访问其他函数作用域中的变量的函数。换言之就是有不是自己变量的函数,就是闭包。
创建闭包的常见方式,就是在一个函数内部创建另一个函数。
详细理解作用域链: 在后台执行环境中,闭包的作用域链包含着它自己的作用域、包含函数的作用域和全局作用域

function createComparisonFunction(propertyName) {      
    return function(object1, object2){ 
        var value1 = object1[propertyName]; 
        var value2 = object2[propertyName];          
        if (value1 < value2){ 
            return -1; 
        } else if (value1 > value2){ 
            return 1; 
        } else { 
            return 0; 
        } 
    }; 
}
var compareNames = createComparisonFunction("name"); //创建函数 
var result = compareNames({ name: "Nicholas" }, { name: "Greg" }); //调用函数 
compareNames = null; //解除对匿名函数的引用(以便释放内存) 

作用域链

var name = "The Window"; 
var object = { 
    name : "My Object", 
    getName: function(){ 
        return this.name; 
    } ,
    getNameFunc : function(){
        var that = this; //这一行是关键,通常也有let self = this的默认命名
        return function(){ 
            return that.name; 
        }; 
    } 
};
alert(object.getNameFunc()());  //"My Object"

模仿块级作用域

其中的变量 now 现在是匿名函数中的局部变量,而我们不必在全局作用域
中创建它。

(function(){ 
    var now = new Date(); 
    if (now.getMonth() == 0 && now.getDate() == 1){ 
        alert("Happy new year!"); 
    } 
 }
)(); 

模拟私有变量(模块模式)

JavaScript 是以对象字面量的方式来创建单例对象的。简言之,如果必须创建一个对象并以某些数据对其进行初始化,同时还要公开一些能够访问这些私有数据的方法,那么就可以使用模块模式。

var application = function(){ 
    var components = new Array();     //私有变量和函数 
    components.push(new BaseComponent());     //初始化 

    var app = new BaseComponent();  //创建 application 的一个局部副本 
    //公共接口 
    app.getComponentCount = function(){ 
        return components.length; 
    }; 
    app.registerComponent = function(component){ 
        if (typeof component == "object"){ 
            components.push(component); 
        } 
    }; 

     return app; 
}(); 
    //返回这个副本 

在 Web 应用程序中,经常需要使用一个单例来管理应用程序级的信息。这个简单的例子创建了一个用于管理组件的 application 对象。在创建这个对象的过程中,首先声明了一个私有的 components数组,并向数组中添加了一个 BaseComponent 的新实例(在这里不需要关心 BaseComponent 的代码,我们只是用它来展示初始化操作)。而返回对象的 getComponentCount()和 registerComponent()方法,都是有权访问数组 components的特权方法。前者只是返回已注册的组件数目,后者用于注册新组件。