函数表达式在使用前必须先赋值。
// 函数表达式,使用前必须先赋值
var functionName=function(arg0,arg1){}//匿名函数或拉姆达函数
// arguments.callee 是一个指向正在执行的函数的指针,因此可以用它来实现对函数
// 的递归调用,
function factorial(num){
if(num<1){
return 1;
}else{
return num*arguments.callee(num-1);
}
}
console.log(factorial(5));
//在不允许使用arguments.callee的情况下可以使用 函数表达式
var fac=(function f(num){
if(num<1){
return 1;
}else{
return num*f(num-1);
}
});
console.log(fac(5));
View Code
闭包是指有权访问另一个函数作用域的变量的函数。
当某个函数被调用时,就会创建一个执行环境及响应的作用域链,然后使用arguments和其他命名参数来初始化函数的活动对象。但在作用域链中,外部函数的活动对象始终处于第二位,外部函数的外部函数处于第三位。。。,直至作为作用域链终点的全局执行环境。
后台的每个执行环境会有一个表示变量的对象---变量对象。全局变量的对象一直存在,其他函数的变量对象,只在函数执行时存在。无论什么时候搜索变量时都会从作用域链中搜索具有相应名字的变量。当函数执行完成后,会将局部活动对象销毁。在另一个函数中定义的函数会将包含函数的活动对象添加到作用域链中。
闭包只能取得包含函数中的任何变量的最后一个值.
关于this对象
在全局函数中this=window,而当函数作为某个对象的方法调用时,this等于那个对象。不过匿名函数的执行环境具有全局性,因此其this对象通常指向window。但有时候不那么明显。
var name="the window";
var object={
name:"My Object",
getName:function(){
return function(){
return this.name;
}
}
}
alert(object.getName()());
View Code
每个函数在调用时都会自动获取两个特殊的变量:this和arguments。内部函数搜索这两个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量。把外部作用域中的this保存到闭包内能够访问的变量里,就可以让闭包访问该对象了。
模仿块级作用域
用作块级作用域(私有作用域)的匿名函数语法如下:
(function(){})();
将函数声明包括在一对圆括号内,表示它实际上是一个函数表达式。而紧随其后的另一对圆括号会立即调用这个函数。
// alert(object.getName()());
// 模仿块级作用域
function outputNumbers(count){
(function(){//定义私有作用域
for(var i=0;i<count;i++){
console.log(i);
}
})();
console.log(i);//输出 undefined
}
outputNumbers(5);
View Code
在匿名函数中定义的任何函数都会在执行结束后销毁。这种技术经常在全局作用域中被用在函数外部,从而显示向全局作用域中添加过多的变量和函数。
同样可以减少闭包占用的内存问题,因为没有指向匿名函数的引用。只要函数执行完毕就销毁其作用域链。
私有变量
在函数内定义的变量,外部无法访问。
如果在函数创建一个闭包,那么闭包就可以通过自己的作用域链访问这些变量。利用这一点可以创建用于访问私有变量的公有方法。
把有权访问私有变量和私有函数的方法称为特权方法。
在构造函数中定义特权方法:
基本模式如下
function MyObject(){ //私有变量和私有函数 var privateVariable=10; function privateFunction(){ console.log(privateVariable); return false; } this.publicMethod=function(){ privateVariable++; return privateFunction(); } }
缺点:必须使用构造函数模式来达到这个目的。
静态私有变量
(function (){ var privateVariable=10; function privateFunction(){ console.log(privateVariable); return false; } MyObject=function(){}; MyObject.prototype.publicMethod=function(){ privateVariable++; return privateFunction(); } })();
以这种方式创建静态私有变量会因为使用原型而增进代码复用,但每个实例都没有自己的私有变量。到底是使用实例变量,还是静态私有变量,最终还是要视你的具体需求而定。
模块模式
模块模式为单例创建私有变量和特权方法。
var application=function(){ //私有变量和函数 var components=new Array(); components.push(new BaseComponent()); //公共 return { getComponentCount:function(){ return components.length; }, registerComponent:function(){ if(typeof component == "object"){ components.push(components); } } }; }();
简言之,如果必须创建一个对象并以某些数据对其进行初始化,同时还要公开一些能够访问这些私有数据的方法,那么就可以使用模块模式。以这种模式创建的每个单例都是 Object 的实例,因为最终要通过一个对象字面量来表示它。
增强的模块模式
在返回对象之前加入对其增强的代码。这种增强的模块模式适合那些单例必须是某种类型的实例,同时还必须添加某些属性或方法对其加以增强的情况。
BaseComponent = function(){} var application=function(){ //私有变量和函数 var components=new Array(); //components.push(new BaseComponent()); var app=new BaseComponent(); app.getComponentCount=function(){ console.log(components.length); } app.registerComponent=function(component){ if(typeof component == "object") components.push(component); } return app; //公共 // return { // getComponentCount:function(){ // return components.length; // }, // registerComponent:function(){ // if(typeof component == "object"){ // components.push(components); // } // } // }; }(); application.registerComponent(new BaseComponent()); application.getComponentCount();