1

函数表达式

递归

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

    function factrial(num){
      if(num<=1){
        return 1;
      }else {
        return num*factrial(num-1);
      }
    }
  • argument.callee是一个指向正在执行的函数的指针,因此可以用它来实现对函数的递归调用

    function factorial(num){
      if(num<=1){
        return 1;
      }else {
        return num*argument.callee(num-1)
      }
    }
  • 严格模式下不能通过脚本访问argument.callee,访问这个属性会导致错误,不过可以使用命名函数表达式类达成相同的结果

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

闭包

  • 闭包是指有权访问另一个函数作用域中的变量的函数

    function compare(value1,value2){
      if(value1<value2){
        return -1;
      }else if(value1>value2){
        return 1;
      }else {
        return 0;
      }
    }
    var result=compare(5,10)

    图片描述

    //创建函数
    var compareNames = createComparisonFunction("name");
    //调用函数
    var result = compareNames({ name: "Nicholas" }, { name: "Greg" });
    //解除对匿名函数的引用(以便释放内存)
    compareNames = null;

    图片描述

闭包与变量

  • 闭包只能取得包含函数中任何变量的最后一个值,i值为10

    function creatFunctions(){
      var result=new Array();
      for(var i=0;i<10;i++){
        result[i]=function(){
          return i;
        };
      };
      return result;
    }
  • 通过匿名函数强制让闭包的行为符合预期

    function createFuntion(){
      var result=new Array();
      for(var i=0;i<10;i++){
        result[i]=function(num){
          return function(){
            return num;
          };
        }(i);
      }
      return result;
    }

关于this对象

  • 匿名函数的执行环境具有全局性,因此其this对象通常指向window
  • 把外部作用域中的this对象保存在一个闭包能够访问到的变量里,就可以了让闭包访问这个对象了

    var name="The Window";
    var object={
      name:"My Object",
      getNameFunc:function(){
        var that=this;
        return function(){
          return that.name
        };
      }
    };
    alert(object.getNameFunc()());//"My Object"
  • 定义米明函数之前,我们把this对象赋值给了一个名叫that的变量,而在定义了这个闭包之后,闭包也可以访问这个变量,因此它是我们在包含函数中特意声明的一个变量,即使在函数返回之后,that也仍然引用这object

内存泄漏

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

    function assignHandler(){
      var element=docunemt.getElementById("someElement");
      element.onclick=function(){
        alert(element.id)
      }
    }
  • 以上代码段中的element占用的内存永远不会被回收

    function assignHandler(){
      var element=document.getElementById("someElement");
      var id=element.id;
      element.onclick=function(){
        alert(id);
      }
      element=null;
    }

模仿块级作用域

function outputNumbers(count){
  for(var i=0;i<count;i++){
    alert(i);
  }
  var i;//重新声明变量
  alert(i);//计数
}
  • JavaScript从来不会告诉你是否多次声明了同一个变量,遇到这种情况,只会对后续的声明视而不见,不过会执行后续声明中的变量初始化。匿名函数可以用来模仿块级作用域来避免这个问题

    (function(){
      //这里是块级作用域
    })()
  • 代码定义并立即调用了一个匿名函数,将函数声明包含在一对圆括号中,表示它实际上是一个函数表达式,而紧随其后的另一对圆括号会立即调用这个函数。

    function outputNumbers(count){
      (function(){
        for(var i=0;i<count;i++){
          alert(i)
        }
      })();
      alert(i);//导致一个错误
    }
  • 这种技术经常在全局作用域中被用在函数外部,从而限制向全局作用域中添加过多的变量和函数。一般来说,我们应该尽量少向全局作用域中添加变量和函数

私有变量

  • JavaScript中灭有私有成员的概念,所以对象属性都是共有的。任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数的外部访问这些变量,私有变量包括函数的参数、局部变量和在函数内部定义的其他函数。
  • 如果在函数内部创建一个闭包,那么闭包通过自己的作用域链也可以访问函数内的变量

静态私有变量

(funciton(){
  //私有变量和私有函数
  var privateVariable=10;
  function privateFunction(){
    return false;
  }
  //构造函数
  MyObject=function(){}
  //公有/特权方法
  MyObject.prototype.publicMethod=function(){
    privateVariable++;
    return privateFunciton();
  }
})();
  • 在私有作用域中,首先定义了私有变量和私有函数,然后又定义了构造函数及其公有方法

模块模式

  • 模块模式是为单例创建私有变量和特权方法。单例指的就是只有一个实例的对象。按照惯例,JavaScript是以字面量的方式来创建单例对象的

    var singleton={
      name:value,
      method:function(){
        //这里是代码方法
      }
    }
  • 模块模式通过为单例添加私有变量和特权的方法能够使其得到增强

    var singleton=function(){
      //私有变量和私有函数
      var privateVariable=10;
      funciton privateFunction(){
        return false;
      }
      //特权/公有方法和属性
      return {
        publicProperty:true,
        publicMethod:function(){
          privateVariable++;
          return privateFunction();
        }
      };
    }();

增强的模块模式

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;
}();

神膘护体小月半
406 声望6 粉丝