Blogger Information
Blog 22
fans 0
comment 1
visits 17608
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
第十章深入理解闭包
刘静的博客
Original
623 people have browsed it

第十章深入理解闭包

理解闭包

作用域:全局作用域和函数作用域

闭包就是fn2,既能够读取其它函数内部变量的函数

[^定义在一个函数内部的函数]:

闭包最大的特点:就是它可以记住诞生的环境,比如fn2记住了它诞生的环境是fn1,所以在fn2中可以得到fn1中的内部变量

[^本质上:闭包就是函数内部和函数外部链接的一座桥梁。]:

  1. var a = 123;
  2. function fn1(){
  3. console.log(a);
  4. var b = 234;
  5. function fn2(){
  6. console.log(b);
  7. }
  8. return fn2;
  9. }
  10. var result = fn1();
  11. result();//b is not defined

闭包的用途

1.通过闭包制作计数器

[^作用:读取函数内部的变量,这些变量始终在内存中,使用闭包小心内存的泄露]:

  1. function a(){
  2. var start = 0;
  3. function b(){
  4. return start++;
  5. }
  6. return b;
  7. }
  8. var inc = a();
  9. console.log(inc());
  10. console.log(inc());
  11. console.log(inc());
  12. // 释放当前的变量
  13. inc = null;

2.闭包能够封装对象的私有属性和方法

  1. function Person(name){
  2. //私有的属性
  3. var age;
  4. //私有的方法
  5. function setAge(n){
  6. age = n;
  7. }
  8. function getAge(){
  9. return age;
  10. }
  11. return {
  12. name:name,
  13. setAge:setAge,
  14. getAge:getAge
  15. }
  16. }
  17. var p1 = Person('mjj');
  18. p1.setAge(18);
  19. console.log(p1.getAge());
  20. p1 = null;

闭包的注意点

1.使用闭包使得函数中的变量始终在内存中,内存消耗很大,所以不能滥用闭包.否则会造成页面的性能问题.在ie中可能导致内存泄露.

2.变量用完不会被销毁,函数用完会销毁,私有属性会被存储起来

3.每个父函数调用完成,都会形成新的闭包,父函数中的变量始终会在内存中,相当于缓存,小心内存的消耗问题

4.闭包需要三个条件:1.函数嵌套 ;2.访问所在的作用域 ;3.在所在作用域外被调用

立即执行函数(IIFE)

IIFE: ()是表达式 跟在函数后面 表示调用函数 fn()

立即执行函数:定义函数之后,立即调用该函数,这种函数叫做立即执行函数

[^注意: 如果function出现在行首 一律解释成函数声明语句]:

简称:自执行函数

  1. //1.常用的两种写法
  2. (function(){
  3. })()
  4. !(function(){
  5. }());
  6. //2.通常情况下,写自执行函数的时候
  7. !(function(){})();

自执行函数的应用

计数器

  1. // 1.全局变量,会污染这个全局的变量
  2. var a = 0;
  3. function add(){
  4. return ++a;
  5. }
  6. console.log(add());
  7. console.log(add());
  8. console.log(add());
  9. console.log(add());
  10. console.log(add());
  11. // 2.自定义属性 有些代码可能会无意修改add.count
  12. function add(){
  13. return ++add.count;
  14. }
  15. add.count = 0;
  16. console.log(add());
  17. console.log(add());
  18. console.log(add());
  19. console.log(add());
  20. // 立即执行函数也叫闭包,可以封装私有的属性,同时可以减少对全局变量的污染
  21. var add = (function (){
  22. // 私有属性
  23. var count = 0;
  24. return function (){
  25. return ++count;
  26. }
  27. })();
  28. var add2 = (function(){
  29. var count = 1;
  30. })();
  31. console.log(add);
  32. console.log(add());
  33. console.log(add());
  34. console.log(add());
  35. console.log(add());
  36. console.log(add());
  37. console.log(add());

对循环和闭包的理解错误

  1. function foo(){
  2. var arr = [];
  3. for(var i = 0; i < 10; i++){
  4. arr[i] = function(){
  5. return i;
  6. }
  7. }
  8. return arr;
  9. }
  10. var bar = foo();
  11. console.log(bar[0]());//10
  12. console.log(bar[5]());//10

解决方案:

1.使用闭包解决循环中变量的问题,相当于把变量保存在内存中,,每次执行的时候从内存中获取

  1. function foo(){
  2. var arr = [];
  3. for(var i = 0; i < 10; i++){
  4. arr[i] = (function(n){//第一种写法
  5. return function(){
  6. return n;
  7. }
  8. })(i);
  9. (function(n){//第二种写法
  10. arr[n] = function(){
  11. return n;
  12. }
  13. })(i);
  14. }
  15. return arr;
  16. }
  17. var bar = foo();
  18. console.log(bar);
  19. console.log(bar[0]());
  20. console.log(bar[1]());
  21. console.log(bar[2]());
  22. console.log(bar[3]());
  23. console.log(bar[4]());

2.解决方法 let块级作用域 ES6

  1. function foo(){
  2. var arr = [];
  3. for(let i = 0; i < 10; i++){
  4. arr[i] = function(){
  5. return i;
  6. }
  7. }
  8. return arr;
  9. }
  10. var bar = foo();
  11. console.log(bar[0]());
  12. console.log(bar[1]());
  13. console.log(bar[2]());
  14. console.log(bar[3]());

[^MJJ名言:在编程,如果实际和预期结果不符,就按照代码执行顺序一步一步地把执行环境图示画出来,会发现很多时候我们都是在想当然]:

闭包的10种表示形式

1.返回值 最常见的一种形式

  1. var fn = function(){
  2. var name = 'mjj';
  3. return function(){
  4. return name;
  5. }
  6. }
  7. var fnc = fn();
  8. console.log(fnc());

2.函数赋值 一种变形的形式是将内部函数赋值给一个外部的变量

  1. var fn2;
  2. var fn = function(){
  3. var name = 'mjj';
  4. var a = function (){
  5. return name;
  6. }
  7. fn2 = a;
  8. }
  9. fn();
  10. console.log(fn2());

3.函数参数

  1. function fn2(f) {
  2. console.log(f());
  3. }
  4. function fn() {
  5. var name = 'mjj';
  6. var a = function() {
  7. return name;
  8. }
  9. fn2(a);
  10. }
  11. fn();

4.IIFE

  1. function fn3(f) {
  2. console.log(f());
  3. }
  4. (function() {
  5. var name = 'alex';
  6. var a = function() {
  7. return name;
  8. }
  9. fn3(a);
  10. })();

5.循环赋值

  1. function foo() {
  2. var arr = [];
  3. for (var i = 0; i < 10; i++) {
  4. (function(i){
  5. arr[i] = function(){
  6. return i;
  7. }
  8. })(i);
  9. arr[i] = (function(n) {
  10. return function() {
  11. return n;
  12. }
  13. })(i);
  14. }
  15. return arr;
  16. }
  17. var bar = foo();
  18. console.log(bar[3]());

6.getter和setter函数来将要操作得变量保存在函数内部,防止暴露在外部

  1. var getValue, setValue;
  2. (function() {
  3. var num = 0;
  4. getValue = function() {
  5. return num;
  6. }
  7. setValue = function(v) {
  8. if (typeof v === 'number') {
  9. num = v;
  10. }
  11. }
  12. })();
  13. console.log(getValue());
  14. setValue(10);
  15. console.log(getValue());

7.迭代器(计数器)

  1. var add = function() {
  2. var num = 0;
  3. return function() {
  4. return ++num;
  5. }
  6. }();
  7. console.log(add());
  8. console.log(add());
  9. //['alex','mjj','阿黄']
  10. function setUp(arr) {
  11. var i = 0;
  12. return function() {
  13. return arr[i++];
  14. }
  15. }
  16. var next = setUp(['alex', 'mjj', '阿黄']);
  17. console.log(next());
  18. console.log(next());
  19. console.log(next());

8.区分首次

  1. var firstLoad = (function() {
  2. var list = [];
  3. return function(id) {
  4. if (list.indexOf(id) >= 0) {
  5. //list已经有id
  6. return false;
  7. } else {
  8. // 首次调用
  9. list.push(id);
  10. return true
  11. }
  12. }
  13. })();
  14. console.log(firstLoad(10));
  15. console.log(firstLoad(10));
  16. console.log(firstLoad(30));
  17. console.log(firstLoad(40));
  18. console.log(firstLoad(40));

9.缓存机制

9.1 未加入缓存

  1. function mult(){
  2. // arguments
  3. var sum = 0;
  4. for(var i = 0; i < arguments.length; i++){
  5. sum = sum + arguments[i];
  6. }
  7. return sum;
  8. }
  9. console.log(mult(1,2,3,1,1,2,3)); //求和
  10. console.log(mult(1,2,3,1,1,2,3)); //求和
  11. console.log(mult(1,2,3,1,1,2,3,4)); //求和

9.2 有缓存机制

  1. // 模拟一个对象的key 看该对象中是否有相同的key,如果有则直接获取value返回
  2. {
  3. key:value
  4. 1,2,3,1,1,2,3: 18,
  5. 1,2,3,1,1,2,3,4: 22
  6. }
  7. var mult = function(){
  8. // 缓存对象
  9. var cache = {};
  10. var calculate = function (){
  11. var sum = 0;
  12. for(var i = 0; i < arguments.length; i++){
  13. sum = sum + i;
  14. }
  15. return sum;
  16. }
  17. return function (){
  18. // 对cache对象进行操作
  19. // 1,2,3,1,1,2,3
  20. var args = Array.prototype.join.call(arguments,',');
  21. if(args in cache){
  22. return cache[args];
  23. }
  24. console.log(cache);
  25. return cache[args] = calculate.apply(null,arguments);
  26. }
  27. }();
  28. console.log(mult(1,2,3,1,1,2,3));
  29. console.log(mult(1,2,3,1,1,2,3));
  30. console.log(mult(1,2,3,1,1,2,3,10,20));
  31. console.log(mult(1,2,3,1,1,2,3,10,20,1));

10.img图片对象上报

new Image() 进行数据上报

低版本浏览器在进行数据上报会丢失30%左右的数据

  1. // 使用闭包来做图片上传
  2. var report = function (src){
  3. var imgs = [];
  4. return function (src){
  5. var img = new Image();
  6. imgs.push(img);
  7. img.src = src;
  8. }
  9. }();
  10. report('http://xxx.com/getUserInfo');
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!