第7章 函数表达式

var functionName=function(arg0,arg1,arg2){

      //函数体

};

alert(functionName.name);// functionName

这种情况下创建的函数叫做匿名函数(拉姆达函数)匿名函数的name属性时空字符串。

7.1 递归

递归函数是通过名字调用自身的情况下构成的

function factorial(num){

   if(num<=1){return 1;

}  else{

return num*factorial(num-1);

}//于函数名有紧密耦合,一旦函数名修改,语句中的函数名也要修改,否则不能完成递归

}

function factorial(num){

   if(num<=1){return 1;

}  else{

return num*arguments.callee(num-1);

}//消除了于函数名的紧密耦合

}

在严格模式下不能通过脚本访问arguments.callee。可以使用命名函数表达式来达成相同的结果

var factorial=(function f(num){

      if(num<=1){

             return 1;

}else{

       return num*f(num-1);

}

});

7.2 闭包

闭包是指有权访问另一个函数作用域中的变量的函数。常见方式是在函数内部创建另一个函数。

闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用闭包会导致内存占用过多。

7.2.1 闭包与变量

作用域链的配置机制引出了一个值得注意的副作用,即闭包只能取得包含函数中任何变量的最后一个值。例如以下例子每个函数都返回10.

function creatFunctions(){

      var result=new Array();

      for(i=0;i<10;i++){

             result[i]=function(){

                    return i;              

             }

      };

return result;    

}

可以改为,则返回正常结果

function creatFunctions(){

      var result=new Array();

      for(i=0;i<10;i++){

             result[i]=(function(){

                    return i;              

             })();

      }

return result;    

            }

7.2.2 关于this对象

在全局函数中,this指向window,但函数作为某个对象的方法调用时,this等于那个对象。不过,匿名函数的执行环境具有全局性,因此其this对象通常指向window。

var name=”the window”;

var object={

      name: “My object”;

      getNameFunc: function(){

             return function(){

                    return this.name;

};

      }

}

alert(object.getNameFunc()());//the window

var name=”the window”;

var object={

      name: “My object”;

      getNameFunc: function(){

             var that=this;

             return function(){

                    return that.name;

};

      }

};

alert(object.getNameFunc()());//My object

7.2.3内存泄漏

如果闭包的作用域链中保存着一个HTML元素,那么久意味着该元素无法被销毁。

7.3 模仿块级作用域

JavaScript没有块级作用域的概念。变量在函数内部定义后就可以在函数内部随处访问他。

function outputNambers(count){

      for (var i=0; i<count;i++){

       alert(i);

}

      alert(i);//计数

}

 

function outputNambers(count){

      for (var i=0; i<count;i++){

       alert(i);

}

var i;//重新声明变量,对结果没影响

      alert(i);//计数

}

 

 

 

 

 

匿名函数可以用来模仿块级作用域

function outputNambers(count){

      (function(){

for (var i=0; i<count;i++){

       alert(i);

}

           })();//创建一个函数并立即调用,调用完其定义的变量会立即销毁

      alert(i);//导致一个错误

}

这种做法可以减少闭包占用的内存问题,因为没有指向匿名函数的引用,只要函数执行完毕,就可以立即销毁其作用域链。

7.4 私有变量

任何函数定义的变量都可以认为是私有变量,因为不能在函数的外部访问这些变量。私有变量包括函数的参数、局部变量和在函数内部定义的其他函数。

function add(num1,num2){

      var sum=num1+num2;

      return sum;

}// 有三个私有变量: num1、num2和sum.

特权方法:有权访问私有变量和私有函数的共有方法称为特权方法。即在函数外部,只有通过调用特权方法才能访问函数内部的私有变量或私有函数。

function MyObject(){

      //私有变量和私有函数

      var privateVatiable=10;

      function privateFunction(){

             return false;

}

//特权方法

this.publicMethod=function(){

       privateVariable++;

       return privateFunction();

};

}

利用私有和特权成员可以隐藏那些不应该被直接修改的数据,如

function Person(name){

      this.getName=function(){

       return name;

};

      this.setName=function(value){

             name=value;

};

}

var person1=new Person(“YaoMing”);

alert(person1.getName());//YaoMing

person1.setName(“Greg”);

alert(person1.getName());//Greg

7.4.1 静态私有变量

(function(){

      //私有变量

var name=””;

      //构造函数,没有使用函数声明,Person是一个全局变量。

Person=function(value){

       name=value;

};

//公有、特权方法。作为一个闭包,总是包含对作用域的引用。在原型上定义的,所有实例都是用同一个函数

Person.prototype.getName=function(){

       return name;

};

Person.propotype.setName=function(value){

       name=value;

};

})();

var person1=new Person(“Nicholas”);

person1.setName(“Greg”);

alert(person1.getName);//Greg

var person2=new Person(“Michael”);

alert(person1.getName);//Michael

alert(person2.getName);//Michael

这个例子中Person构造函数与getName()和setName()方法一样都有权访问name。在这种模式下,name就变成了一个静态的、由所有实例共享的属性。

以这种方式创建静态私有变量会因为使用原型而增进代码复用,但每个实例都没有自己的私有变量。

7.4.2 模块模式

前面所说的方法是为自定义类型创建私有变量和特权方法,而道格拉斯所说的模块模式则是为单例创建私有变量和特权方法。这种模式在需要对单例进行某些初始化,同时又需要维护其私有变量时是非常有效的。

JavaScript中是以字面量的方式来创建单例对象的。

var singleton={

      name: value;

      method: function(){

             //这里是方法代码

};

}

模块模式通过为单例添加私有变量和特权方法能够使其得到加强,语法如下:

var singleton=function(){

      //私有变量和函数

      var privateV=10;

      function privateFunction(){

             return false;

}

//返回对象字面量只包含可以公开的属性和方法,这个对象字面量定义是单例的公共接口。

return{

       publicProperty: true;

       publicMethod: function(){

              privateV++;

              return privateFunction();

}

};

}();

如果必须创建一个对象并对某些数据进行初始化,同时还要增加一些能够访问这些私有数据的方法,那么就可以使用这种模式。

7.4.3增强的模块模式

进一步改进了模块模式,即在返回对象之前加入对其增强的代码。这种增强的模块模式适合那些单例必须是某种类型的实例,同时还必须添加某些属性或方法对其加以增强的情况

var singleton=function(){

      //私有变量和函数

      var privateV=10;

      function privateFunction(){

             return false;

}

var object=new CustomType();

object.publicProperty: true;

       object.publicMethod: function(){

              privateV++;

              return privateFunction();

};

return object;

}();

 

 

猜你喜欢

转载自blog.csdn.net/willard_cui/article/details/81255345