闭包.词法作用域#

Posted itly

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了闭包.词法作用域#相关的知识,希望对你有一定的参考价值。

JS程序的执行过程.
1.词法分析 .  语法分析阶段:变量声明(赋值阶段在执行阶段进行);函数声明带函数赋值.
2.函数表达式的变形
  1. //函数表达式的变形
  2. var fn=function foo(){
  3. console.log("abc");
  4. };
  5. fn();//"abc" foo();//报错
 
2.词法作用域,作用域链,变量查找过程
按照书写个还是决定了变量可访问的范围,跟调用方式无关
  1. var height =10;
  2. setTimeout(function(){
  3. var height2=30;
  4. setTimeout(function(){
  5. var height1 =80;
  6. console.log(height2);//30
  7. });
  8. console.log(height1);//获取不到height1
  9. });
3.函数具有独立的作用域,在函数内部的程序执行过程,也会有一套完整的预解析的步骤.
 
4.拷贝创建对象
  1. /*拷贝创建对象的高级使用方式*/
  2. function hightExtend(){
  3. var key =0, i =0, len = arguments.length;
  4. target =null;
  5. if(len ==0){
  6. returnfalse;
  7. }elseif(len ==1){
  8. return arguments[0];
  9. }else{
  10. i++;
  11. target = arguments[0];
  12. for(; i < len; i++){
  13. for(key in arguments[i]){
  14. target[key]= arguments[i][key];//把后面传入的对象遍历一下,但遍历每一个对象的属性
  15. //添加到target元素上
  16. }
  17. }
  18. }
  19. }
  1. //5.历史遗留问题
  2. if(true){
  3. function foo1(){
  4. console.log(foo1);
  5. }
  6. }else{
  7. function foo2(){
  8. console.log(foo2);
  9. }
  10. }
  11. //在ff.chrome中打印结果为f1,在旧版本中打印结果为f2
  12. //规则规范,不允许在语法块中声明函数
  13. 6.跨作用域访问变量
  1. /*
  2. * 查找作用域中的变量:首先查找当前作用域是否定义了该变量,若果定义了就不会再继续查找
  3. * */
  4. function foo(a,b){
  5. console.log(a);}
  6. foo(1,4);
  7. //函数的参数是在foo作用域执行的时候
  8. //预解析:分析a是一个采纳数所以会向当前作用域添加一个变量a并且给a赋值,值是实参的值
  9. //代码执行;参数已经有值了 可以直接获取
  10. var num =10;
  11. function fn(num){
  12. console.log(num);//undefined
  13. // 首先查找当前作用域是否定义了num
  14. }
 
3.闭包  模块化   闭包最常见的使用场景
  1. //沙箱:模块化,沙箱是一个隔离的环境,最大的好处就是避免全局变量的污染.
  2. var model =(function(){//一个匿名的立即执行函数
  3. var price =900;//这是一个model局部的变量,外界无法访问,无法修改
  4. //有效的保障了属性的安全性
  5. return{
  6. pay:function(money){
  7. if(money < price){
  8. console.log("您的消费不够,请继继续消费");
  9. }else{
  10. console.log("恭喜成为VIP");
  11. }
  12. }
  13. }
  14. })();
  15. console.log(model.pay(800));//"消费不够.." undefined
  16. model.pay(1000);//"VIP..."
  17. //千万注意不用打印,pay函数本身就有输出,如果在console.log中
  18. //会输出函数的返回值.
 
  1. //在面向对象中使用沙箱
  2. //应用场景:在页面初始化的时候要用到f1,f2,f3三个函数
  3. //这三个函数不想让外界访问,需要把这单个方法声明成为构造函数
  4. //内部私有的变量
  5. var songManger =(function(){
  6. function f1(){
  7. console.log("函数f1的方法");
  8. }
  9. function f2(){
  10. console.log("函数f2的方法");
  11. }
  12. function f3(){
  13. console.log("函数f4的方法");
  14. }
  15. functionSongManger(){//声明一个构造函数
  16. }
  17. SongManger.prototype={//在原型对象上扩展方法
  18. init:function(){
  19. f1();
  20. f2();
  21. f3();
  22. }
  23. };
  24.   // return SongManger;//注意这个返回的是构造函数,使用之前需要先实例化一下
  25. returnnewSongManger;//把构造函数返回,实例化一下,这样外边就不需要实例化了
  26. })();
  27. songManger.init();//
 
  1. /*
  2. * 闭包实现缓存
  3. * 属性:有个键--值 --->所以可以将缓存数据存放在一个对象中
  4. * 方法:缓存存储 setCache
  5. * 缓存的获取 getCache
  6. * */
  7. function configCache(){
  8. var obj={};//设置一个内部的对象 用来存储缓存数据;这个属性是私有的
  9. //对外暴露两个公共的方法
  10. return{
  11. setCache:function(k,v){//设置缓存
  12. obj[k]=v;
  13. },
  14. getCache:function(k){//获取缓存
  15. return obj[k];
  16. }
  17. };
  18. }
  19. var conf = configCache();
  20. console.log(conf);
  21. conf.setCache(1,\'sdwqecwqv\');
  22. console.log(conf.getCache(1));//sdwqecwqv
  23. /*
  24. * 注意下面这种情况,两次configCache()会产生不同的执行环境
  25. * */
  26. configCache().setCache(1,\'sdwqecwqv\');
  27. console.log(configCache().getCache(1));//undefined
  28. /*
  29. * 使用立即执行函数
  30. * */
  31. var cacheConfig =(function(){
  32. var obj={};
  33. return{
  34. setCache:function(k,v){
  35. obj[k]=v;
  36. },
  37. getCache:function(k){
  38. return obj[k];
  39. }
  40. }
  41. })();
 
  1. // 给所有的 li 提供点击事件, 在点击后 弹出目录中的文本内容
  2. <body>
  3. <ul>
  4. <li>aaa</li>
  5. <li>bbb</li>
  6. <li>ccc</li>
  7. <li>ddd</li>
  8. <li>eee</li>
  9. </ul>
  10. </body>
  11. <script>
  12. var list = document.getElementsByTagName(\'li\');
  13. for(var i =0; i < list.length; i++){
  14. list[ i ].onclick =function(){
  15. //alert(i);//i=5
  16. //alert( list[ i ].innerhtml );//报错
  17. //alert(this.innerHTML);//一种解决方案
  18. //list[4]:eee list[5]:undefined
  19. };
  20. }
  21.  
  22. </script>
  1. //第二种解决方案:闭包
  2. // for ( i = 0; i < list.length; i++ ){
  3. var j=i;
  4. // list[ i ].onclick = (function (j) {
  5. // return function (){
  6. // alert(list[j].innerHTML);
  7. // }
  8. // }(i));
  9. // }
 
 
 
  1. //caller
  2. function fn1(){
  3. console.log(fn1.caller);//打印的是fn1函数体
  4. }
  5. function fn2(){
  6. fn1();
  7. }
  8. fn2();
  9. console.log(fn1.caller);//null caller方法只能在函数调用的时候获取
 
  1. //问题理解的关键: 内层函数保存的j,当执行的时候从哪里取的??
  2. //每次绑定都会执行一个外层函数,都会产生一个新的作用域,内层函数会保存这个新作用域中的变量
  3. var list = document.getElementsByTagName("li");
  4. for(var i=0;i<list.length;i++){
  5. list[i].onclick=(function(){
  6. var j=i;//每次绑定都会执行外层函数,都会保存一个J的变量在内层函数中
  7. returnfunction(){
  8. console.log(list[j].innerHTML);
  9. }
  10. })();
  11. }
  1. //结论:
  2. //闭包保存一个数据,让外层函数执行一次
  3. //闭包保存多个数据,让外层函数执行多次
  4. var list = document.getElementsByTagName(\'li\');
  5. for(var i =0; i < list.length; i++){
  6. //希望每一次绑定的时候,就保存一下当前的索引
  7. // 多次绑定就保存多个索引——>利用闭包,保存多个数据:让外层函数执行多次
  8. list[i].onclick =(function(){
  9. var j=i;
  10. returnfunction(){//内层函数由浏览器帮助我们调用的
  11. alert(list[j].innerHTML);
  12. }
  13. }());//调用了5次,外层函数调用了五次,就会产生5个独立的作用域,这几个作用域中的j变量的值都不一样
  14. }
 
 
 





以上是关于闭包.词法作用域#的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript之作用域和闭包

理解闭包

JS高级. 05 词法作用域变量名提升作用域链闭包

什么是作用域, 什么事闭包, 什么事原型链

javascript中的闭包

我不知道的js作用域与闭包