理解js中的闭包

时间:2021-02-07 20:36:45

闭包 我的理解是 能够有权访问另一个函数作用域中变量的函数

通常我们知道 普通的函数在调用完成之后,活动对象不会从内存中销毁,其执行环境的作用域链会被销毁,造成资源的浪费 而闭包的好处就在于执行完就会被回收 不会造成资源的极大的浪费 性能也会相应的提升~

闭包的几种写法

 //当只有一个返回的内部函数时候

 //第一种写法
function test1(a,b){ return function(c){
console.log(a + b + c);
} }
var m1 = test1(2,4);
m1(5); //输出 11 //第二种写法 function test2(a,b){
var name = 'xsdsfsfsdxcxcx'; function xx(c){
console.log(a + b + c);
}
return xx;
}
var m2 = test2(2,4);
m2(5); //输出 11

若有多个需要返回的内部函数 可使用对象的方法一一列举出来 又称模块模式

 // 多个返回的内部函数
function test2(a,b){
var name = 'xsdsfsfsdxcxcx'; function xx(c){
console.log(a + b + c);
}
function ss(){
// js中replace默认只替换查找到的第一个值 若要替换多个值需要使用正则
var _replace = name.replace('x','aa');
console.log(_replace);
}
function allReplace(){
var re = /x/g;
var _replace = name.replace(re,'X');
console.log(_replace);
}
return {
xx : xx,
ss : ss,
allReplace: allReplace
}
}
var m2 = test2(2,4);
m2.ss(); //输出 aasdsfsfsdxcxcx
m2.xx(3); //输出 9
m2.allReplace(); //输出 XsdsfsfsdXcXcX

简单的案例看下 静态方法和实例方法的区别

  1 var test1 = function(){
2
3 }
4 test1.Show = function(){
5 alert('静态方法!');
6 }
7 test1.prototype.Display = function(){
8 alert('实例方法!');
9 }
10
11 test1.Show(); //静态方法 只能直接用类名进行调用 不能使用this
                       //函数才有prototype属性 对象是没有的 12 test1.Display(); //报错 这是一个是实例方法 必须先实例化后才能进行调用
13
14
15 var Demo = new test1();
16 Demo.Display(); //实例方法

再来看一段代码

 var dom = function(){
var Name = "Default";
this.Sex = "Boy";
this.success = function(){
alert("Success");
};
}; alert(dom.Name); //undefined 这是因为每个function都会形成一个作用域 而这些变量声明在函数中 所以就处于这个函数的作用域中 外部是无法访问的 必须new一个实例
alert(dom.Sex); //undefined

再来一段代码

 var html = {
Name:'Object',
Success:function(){
this.Say = function(){
alert("Hello,world");
};
alert("Obj Success");
}
};
//html是一个对象,不是函数,所以没有Prototype属性,其方法也都是公有方法,html不能被实例化。
//我们可以这样使用它 html.Name 和 html.Success()
//当然我们也可以将这个对象作为一个值赋给其他变量 比如 var a = html

那么问题来了 我们该如何访问Success方法中的Say方法呢 难道是html.Success.Say()吗? 当然这样式错误的啦  因为在Say方法中又开始了一个新的function形成新的作用域 肯定是访问不到里面的内容啦

得做点修改 比如

  1 var s = new html.Success();
2 s.Say(); //Hello,world
3
4
5 //或者写在外面
6 html.Success.prototype.Show = function(){
7 alert("HaHa");
8 };
9 var s = new html.Success();
10 s.Show();

说了这么多 那么闭包的用途到底是什么呢?

事实上通过使用闭包 我们可以做很多事情 比如模拟面向对象的代码风格 更优雅 更简洁的表达出代码 这是一个有点追求美感的程序员应该做的 而且在某些方面可以提升代码的执行效率

1 匿名自执行函数

 var data  = {
arr : [2,5,2,4,333],
tree : {}
}
(function(x){
var row,
new_arr = [];
for(var i = 0; i < x.arr.length; i ++){
row = x.arr[i];
new_arr.push(row);
}
return new_arr;
})(data) //输出 [2,5,2,4,333]

创建了一个匿名函数 并立即执行 由于外部无法直接访问内部的变量 因此在函数执行完成后会立刻释放资源 还不会污染全局变量

2 缓存作用

将计算结果缓存在内部 之后再调用的话就可以直接使用

3 封装

 var package  = function(){
var name = '张三'; return {
getName : function(){
return name;
},
setName : function(names){
name = names;
return name;
}
}
}(); package.getName(); //张三
package.setName('李四'); // 李四 package.name; //undefined

4 类和继承

 function Mother(){
var eye = 'default'; return {
getName : function(){
return eye;
},
setName : function(newName){
name = newName;
return name;
}
}
} var M = new Mother();
M.getName();
M.setName('beautiful!'); var Person = function(){ }
//继承
Person.prototype = M;
Person.prototype.Say = function(){
console.log('这是私有方法!');
}
var p = new Person();
p.getName();
p.setName('hah');
p.Say();