理解js中的闭包
闭包 我的理解是 能够有权访问另一个函数作用域中变量的函数
通常我们知道 普通的函数在调用完成之后,活动对象不会从内存中销毁,其执行环境的作用域链会被销毁,造成资源的浪费 而闭包的好处就在于执行完就会被回收 不会造成资源的极大的浪费 性能也会相应的提升~
闭包的几种写法
1 //当只有一个返回的内部函数时候 2 3 //第一种写法 4 function test1(a,b){ 5 6 return function(c){ 7 console.log(a + b + c); 8 } 9 10 } 11 var m1 = test1(2,4); 12 m1(5); 13 14 //输出 11 15 16 17 //第二种写法 18 19 function test2(a,b){ 20 var name = 'xsdsfsfsdxcxcx'; 21 22 function xx(c){ 23 console.log(a + b + c); 24 } 25 return xx; 26 } 27 var m2 = test2(2,4); 28 m2(5); 29 30 //输出 11
若有多个需要返回的内部函数 可使用对象的方法一一列举出来 又称模块模式
1 // 多个返回的内部函数 2 function test2(a,b){ 3 var name = 'xsdsfsfsdxcxcx'; 4 5 function xx(c){ 6 console.log(a + b + c); 7 } 8 function ss(){ 9 // js中replace默认只替换查找到的第一个值 若要替换多个值需要使用正则 10 var _replace = name.replace('x','aa'); 11 console.log(_replace); 12 } 13 function allReplace(){ 14 var re = /x/g; 15 var _replace = name.replace(re,'X'); 16 console.log(_replace); 17 } 18 return { 19 xx : xx, 20 ss : ss, 21 allReplace: allReplace 22 } 23 } 24 var m2 = test2(2,4); 25 m2.ss(); //输出 aasdsfsfsdxcxcx 26 m2.xx(3); //输出 9 27 m2.allReplace(); //输出 XsdsfsfsdXcXcX
简单的案例看下 静态方法和实例方法的区别
1 1 var test1 = function(){ 2 2 3 3 } 4 4 test1.Show = function(){ 5 5 alert('静态方法!'); 6 6 } 7 7 test1.prototype.Display = function(){ 8 8 alert('实例方法!'); 9 9 } 10 10 11 11 test1.Show(); //静态方法 只能直接用类名进行调用 不能使用this 12 //函数才有prototype属性 对象是没有的 13 14 12 test1.Display(); //报错 这是一个是实例方法 必须先实例化后才能进行调用 15 13 16 14 17 15 var Demo = new test1(); 18 16 Demo.Display(); //实例方法
再来看一段代码
1 var dom = function(){ 2 var Name = "Default"; 3 this.Sex = "Boy"; 4 this.success = function(){ 5 alert("Success"); 6 }; 7 }; 8 9 alert(dom.Name); //undefined 这是因为每个function都会形成一个作用域 而这些变量声明在函数中 所以就处于这个函数的作用域中 外部是无法访问的 必须new一个实例 10 alert(dom.Sex); //undefined
再来一段代码
1 var html = { 2 Name:'Object', 3 Success:function(){ 4 this.Say = function(){ 5 alert("Hello,world"); 6 }; 7 alert("Obj Success"); 8 } 9 }; 10 //html是一个对象,不是函数,所以没有Prototype属性,其方法也都是公有方法,html不能被实例化。 11 //我们可以这样使用它 html.Name 和 html.Success() 12 //当然我们也可以将这个对象作为一个值赋给其他变量 比如 var a = html
那么问题来了 我们该如何访问Success方法中的Say方法呢 难道是html.Success.Say()吗? 当然这样式错误的啦 因为在Say方法中又开始了一个新的function形成新的作用域 肯定是访问不到里面的内容啦
得做点修改 比如
1 1 var s = new html.Success(); 2 2 s.Say(); //Hello,world 3 3 4 4 5 5 //或者写在外面 6 6 html.Success.prototype.Show = function(){ 7 7 alert("HaHa"); 8 8 }; 9 9 var s = new html.Success(); 10 10 s.Show(); 11
说了这么多 那么闭包的用途到底是什么呢?
事实上通过使用闭包 我们可以做很多事情 比如模拟面向对象的代码风格 更优雅 更简洁的表达出代码 这是一个有点追求美感的程序员应该做的 而且在某些方面可以提升代码的执行效率
1 匿名自执行函数
1 var data = { 2 arr : [2,5,2,4,333], 3 tree : {} 4 } 5 (function(x){ 6 var row, 7 new_arr = []; 8 for(var i = 0; i < x.arr.length; i ++){ 9 row = x.arr[i]; 10 new_arr.push(row); 11 } 12 return new_arr; 13 })(data) //输出 [2,5,2,4,333]
创建了一个匿名函数 并立即执行 由于外部无法直接访问内部的变量 因此在函数执行完成后会立刻释放资源 还不会污染全局变量
2 缓存作用
将计算结果缓存在内部 之后再调用的话就可以直接使用
3 封装
1 var package = function(){ 2 var name = '张三'; 3 4 return { 5 getName : function(){ 6 return name; 7 }, 8 setName : function(names){ 9 name = names; 10 return name; 11 } 12 } 13 }(); 14 15 package.getName(); //张三 16 package.setName('李四'); // 李四 17 18 package.name; //undefined
4 类和继承
1 function Mother(){ 2 var eye = 'default'; 3 4 return { 5 getName : function(){ 6 return eye; 7 }, 8 setName : function(newName){ 9 name = newName; 10 return name; 11 } 12 } 13 } 14 15 var M = new Mother(); 16 M.getName(); 17 M.setName('beautiful!'); 18 19 var Person = function(){ 20 21 } 22 //继承 23 Person.prototype = M; 24 Person.prototype.Say = function(){ 25 console.log('这是私有方法!'); 26 } 27 var p = new Person(); 28 p.getName(); 29 p.setName('hah'); 30 p.Say();