引言:全局变量是魔鬼,我们最好不要与它打交道;
使用闭包的好处是让函数自我管理,通过现有函数生成(return)新的更加实用的函数(闭包返回匿名函数)。
现在我们需要写一个函数,它的功能是将字符串中的HTML实体(例如<>)转换为相应的字符,输入是一个字符串,输出是一个新的字符串。我们可以很容易想到,创建一个字符映射表,根据正则表达式依次替换就可以了。思路很简单,我们尝试一下。
方案一
var entity = {
quot: '"',
lt:'<',
gt:'>'
};
var deentityify = function(str){
return str.replace(/&([^&;]+);/g,function(a,b){
var r = entity[b];
return typeof r ==='string' ? r : a;
});
};
deentityify('>');//output >
在全局作用域内生成了一个映射表entity
,再在全局作用域内声明了函数实体,最后调用它,虽然能达到目的,但是的确不是好的结构风格,毕竟放那么多变量在全局作用域内,到最后是非常难以维护的。
方案二
var deentityify1 = function(str){
//在函数内部声明了entity映射表,确保外界无法访问,避免污染
var entity = {
quot: '"',
lt:'<',
gt:'>'
};
return str.replace(/&([^&;]+);/g,function(a,b){
var r = entity[b];
return typeof r ==='string' ? r : a;
});
};
方案二将entity移动到了函数体内部,这样做可以避免一部分污染,可是我们仔细想一想,在这个函数调用结束之后,entity没有被任何变量所引用,所以它将会被回收,问题来了,在我大量调用这个函数时,将会伴随着entity的多次创建和回收。
方案三-使用闭包
var deentityify2 = function(){
var entity = {
quot: '"',
lt:'<',
gt:'>'
};
return function(str){
if(str !== undefined){
return str.replace(/&([^&;]+);/g,function(a,b){
var r = entity[b];
return typeof r ==='string' ? r : a;
});
}else{
return '请输入参数';
}
};
}();//deentityify2函数实际上得到的是这个匿名函数的返回值
在创建这个函数时,加上()
调用操作符来立即调用,本来entity应该在这个函数结束后被回收的,因为闭包的产生,使一个全局函数deentityify2通过引用一个匿名函数从而引用了entity,导致它并不会被回收,entity作为私有变量,只能通过特权函数deentityify2去访问,实现了信息隐藏。