首页 > 代码库 > 折腾自己的js闭包(二)

折腾自己的js闭包(二)

前面我大致探讨了js里的闭包的相关概念,那么,到底在什么时候用它最好呢?存在即真理,只不过以前没发现它而已,先来看看下面的这几个用途吧

一、我首先想到的就是从函数外面访问它的内部变量,从而达到自己的一些目的,还避免了设定为全局变量的全局变量污染,例如如下这个封装:

var person = function(){    

    //变量作用域为函数内部,外部无法访问    

  var name = "default name";       

  return {    

     getName : function(){  

    return name;    

    },    

     setName : function(newName){    

    name = newName;    

      }    

  }    

}();  

 

console.log(person.name); //结果为undefined    

console.log(person.getName());   //结果为default name

person.setName("xiangxiao");    

console.log(person.getName()); //结果为xiangxiao

 

但是后来想想觉得不大对劲,为何不直接用新建对象的方式来完成呢?或者angular严格的作用域控制其实也可以。要使用的时候就加上 object.变量名/object.方法名();或者在用到angular时的$scope.变量名/$scope.方法名()。猛的反应过来,局部变量,如果用了上述的那些解决办法,那还能叫函数的内部变量吗?不过这种封装的方式在我目前见过的项目里还很少用到。

二、查阅了些资料,发现了它的第二个用途,就是模拟面向对象的基类,对啊,JavaScript虽然没提供明显的类继承,但是仍然有另外的路径来实现同java一样 的继承呀,比如说prototype原型就是一个解决方案,严格的说prototype并不是继承,而是对函数prototype属性的一种拷贝来实现的类似于继承的东西。现在先来看看闭包是怎么模拟的吧,例如:

function Empolyee(){

  var station = "default";  

  return {    

     getStation : function(){  

    return station ;    

    },    

     setStation : function(newStation){    

    station = newStation;    

      }

};

var xiaoming = Empolyee();

console.log(xiaoming.station);  //结果为default

xiaoming.setStation("C++ coder");

console.log(xiaoming.getStation()); //结果为C++ coder

 

var xiaozhang = Empolyee();

console.log(xiaozhang.station); //结果为default

xiaozhang.setStation("java coder");

console.log(xiaozhang.getStation());//结果为java coder

其实仔细一看感觉模拟面向对象这个说法有些牵强,但确实实现了xiaoming和xiaozhang这两个雇员都是来自方法Empolyee的,而且互不影响,xiaoming的岗位是C++程序员,xiaozhang的gangwei是java程序员,相互独立。这点和函数原型prototype超级接近,所以说啊,我们的JavaScript还是包罗万象的。

此处还真的必须用闭包来实现,不写这个return一个对象的话,两个实体的还真没有共同方法setStation和getStation。

 

三、某些只需执行一次的函数,也即是常说的自执行匿名函数,这个在我最近参与的项目里好几处都有用到,基本都是在一个界面的初始化中,初始化需要立马下发一次ajax请求,查上来的数据立马要反馈在页面上显示,而且只需执行这一次即可,内部变量无需再次利用,这时候,用到自执行匿名函数就最合适不过了。例如:

var datamodel = {    

   table : [],    

   tree : {}    

};    

(function(dm){    

  for(var i = 0; i < dm.table.rows; i++){    

    var row = dm.table.rows[i];    

    for(var j = 0; j < row.cells; i++){    

      drawCell(i, j);    

     }    

  };     

})(datamodel); 

这就是一个初始化渲染树结构的自执行匿名函数,我们创建了一个匿名的函数,并立即执行它,由于外部无法引用它内部的变量,因此在执行完后很快就会被释放,关键是这种机制不会污染全局对象。

 

记得以前初识闭包时,遇见过一个经典的闭包的例子,是这样的:

 

折腾自己的js闭包(二)