匿名函数就是没有名字的函数,有时候也称为拉姆达(lambda)函数。
//函数声明 function functionName(){ } //函数表达式 var functionName = function(arg0,arg1,arg2){ } /* *区别: *1函数声明会在代码执行以前被加载到作用域 会指定一个名字 *2函数表达式在代码执行到那一行的时候才会有定义 创建一个匿名函数。赋给变量 */
7.1 递归
递归函数是在一个函数通过名字调用自身的情况下构成的。
arguments.callee是一个指向正在执行的函数的指针,可以实现函数的递归调用
function factorial(num){
if (num <= 1){
return 1;
} else {
return num * factorial(num-1);
}
}
var anotherFactorial = factorial;
factorial = null;
alert(anotherFactorial(4)); //error!
//在编写递归函数时,用arguments.callee比用函数名保险
function factorial(num){
if (num <= 1){
return 1;
} else {
return num * arguments.callee(num-1);
}
}
var anotherFactorial = factorial;
factorial = null;
alert(anotherFactorial(4)); //24
7.2 闭包
闭包是指有权访问另一个函数作用域中的变量的函数。
创建闭包的常见方式,就是在一个函数内部创建另一个函数。
function f1(){ var n = 999; nAdd = function(){ n+=1; } function f2(){ alert(n); } return f2; } var result = f1(); result(); nAdd(); result(); var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()()); var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFunc()());
7.2.1闭包与变量
闭包所保存的是整个变量对象,不是某个特殊的变量。
7.2.2 this对象
this对象是在运行时基于函数的执行环境绑定的。
在全局函数中,this等于window。
当函数被作为某个对象的方法调用时,this等于那个对象。
匿名函数的执行环境具有全局性,this指window
7.2.3内存泄露
如果闭包的作用域链中保存着一个html元素,该元素无法被销毁。必须设为null。function assignHandler(){ var element = document.getElementById("elementId"); var id = element.id;//element.id保存在变量id中 element.onclick = function(){ alert(id); //在闭包中引用该变量消除循环引用 }; element = nul; //将element设为null }
7.3 模仿块级作用域
匿名函数可以用来模仿块级作用域(私有作用域)
(funciton(){ //这里是块级作用域 })();无论在什么地方,只要临时需要一些变量,就可以使用私有作用域。
通过创建私有作用域,每个开发人员既可以使用自己的变量,又不必担心搞乱全局作用域。
这种做法可以减少闭包占用的内存问题。
7.4 私有变量
js没有私有成员的概念,所有对象都是公有的。
任何在函数中定义的变量,都可以认为是私有变量,因为不能再函数的外部访问这些变量。
私有变量包括函数的参数,局部变量和在函数中定义的其他函数。
特权方法: 有权访问私有变量和私有函数的公有方法。
2种创建特权方法的方式。
1 在构造函数中定义特权方法。
function Person(name){ this.getName = function(){ return name; }; this.setName = function(value){ name = value; }; } var person = new Person("flyer"); alert(person.getName()); person.setName("bird"); alert(person.getName());缺点:必须使用构造函数来达到目的。构造函数模式缺点是针对每个实例都会创建同样一组新方法。使用静态私有变量可以避免。
7.4.1 静态私有变量
(function(){ var name = ""; Person = function(value){ name = value; }; Person.prototype.getName = function(){ return name; }; Person.prototype.setName = function (value){ name = value; }; })(); var person = new Person("flyer"); alert(person.getName()); person.setName("bird"); alert(person.getName());
7.4.2 模块模式
道格拉斯所说的模块模式是为单例创建私有变量和特权方法,所为单例,指只有一个实例的对象。
javascript是以对象字面量来创建单例的。
var singleton(){ name: value, method: function(){ //这里是方法的代码 } }模块模式通过为单例添加私有变量和特权方法使其增强:
var singleton = function(){ //返回对象的匿名函数。 //私有变量和私有函数 var privateVariable = 10; function privateFunction(){ return false; } //特权/公有方法和属性 return { publicProperty: true, publicMethod: function(){ privateVariable++; return privateFunction(); } }; }();
7.4.3 增强的模块模式
适合那些单例必须是某种类型的实例,同事还必须添加某些属性和方法对其加以增强的情况。
function BaseComponent(){ } function OtherComponent(){ } var application = function(){ //私有变量和函数 var components = new Array(); //初始化 components.push(new BaseComponent()); //创建application的一个局部副本 var app = new BaseComponent(); //公共接口 app.getComponentCount = function(){ return components.length; }; app.registerComponent = function(component){ if (typeof component == "object"){ components.push(component); } }; //返回这个副本 return app; }(); alert(application instanceof BaseComponent); application.registerComponent(new OtherComponent()); alert(application.getComponentCount()); //2