javascript--13---闭包

获取局部变量

<script>
  function fn1() {
      var a ="月薪10w";
  }
  alert(a);
</script>

如何获取内部变量

  1. 作为函数返回值
<script>
  function fn1() {
      var a ="月薪10w";
      return a;
  }
  alert(fn1());
</script>
  1. 通过变量向外传递
<script>
var b="";
  function fn1() {
      var a ="月薪10w";
     b=a;
  }
  fn1();
  alert(b);
</script>
  1. 通过函数传参
<script>
  function fn1() {
      var a ="月薪10w";
    fn2(a);
  }
  function fn2(str){
      alert(str);
  }
  fn1();
</script>

条件和循环体

<script>
  if (1){
      var a =1;
  } 
  alert(a);
</script>

会有结果1

<script>
 alert(a);
  if (false){
      var a =10;
  } 
</script>

结果是undefined

<script>
  if (1){
      function fn1() {
          
      }
  }
  alert(fn1);

结果是函数体

  1. {}不代表作用域 但是有例外
<script>
 alert(fn1);
  if (1){
      function fn1() {
          
      }
  }

结果是 undefined 这是es6的规范 在es6中 花括号{}会被看作是代码块 在{}当中声明一个函数 相当于 var 声明 所以结果是undefined

<script>
 alert(fn1);
      function fn1() {
          
      }

结果是函数体

  1. 尽量不要在代码块中声明函数 否则 调用会出问题
<script>
fn1();
  if (1){
      function fn1() {
            alert(1);
      }
  }
</script>

会报错 因为此时看作是代码块 相当于var 声明var a=fn1(){}这时候fn1();是不会执行的 会报错

<script>
    alert(fn1);
  if (1){
      function fn1() {
            alert(1);
      }
  }
</script>

结果是个undefined

闭包

<script>
   function t1() {
       var age =20;
       function t2() {
           alert(age);
       }
       return t2;
   }
   var tmp =t1();
   var age =1000;
   tmp();

</script>

结果是 20 AO分析

  • 第1步 AO{t1:function,tmp:un,age:un}
  • 第2步 tmp=t1(); t1执行
    进入函数体 AO{age:un,t2:fun} 执行AO{age:20,t2:fn} 遇到return t2 跳出函数 t2 =function t2(){} 所以 AO{ tmp=t2, age:1000}
  • tmp执行 进入函数t2 AO 没发现变量声明 从上级寻找 age为20
  1. 我们在返回函数的时候 并不是单纯的返回了一个函数 而是把作用域链返回了 如果没有变量声明会沿着作用域链往上找
  2. 函数的作用域 取决于声明时 而不取决于调用时

闭包是什么

  1. 有函数套嵌
  2. 内部函数使用了外部函数的变量
  3. 内部函数的使用外部函数的那些变量和参数会永久保存
  4. 垃圾回收机制:当环境都不存在有某个对象/数据的引用时,这个数据会自动被回收 但是全局变量不会被回收
  5. 返回函数时 并非孤立的函数 而是连同周围的环境 AO 打了一个包 成了一个封闭的环境包 共同返回出来----闭包
<script>
    var age = 10;
   function t1() {
       var age =20;
       return function t2() {
           alert(++age);
       }
   }
   var t3=t1();
   t3();
   t3();
   t3();
   alert(age);

结果 21 22 23 10

console.log(function () {} === function(){});
 console.log([]===[]);
 console.log({}==={});

这些都不一样 不等于

var a =function(){};
    var b =a;
    console.log(a==b);

这是相等的 变量存储 function {} []存储的是个地址

<script>
    var age = 10;
   function t1() {
       var age =20;
       return function t2() {
           alert(++age);
       }
   }
   var t3=t1();
    var t4=t1();
    t3();
    t4();
</script>

结果是 21 21 因为t3 t4 表示的不是一个函数 虽然都是t2

<script>
   function foo() {
       var a=2;
       function baz() {
           console.log(a);
       }
       bar(baz);
   }
    function bar(fn) {
        var a=3;
        fn();
    }
    foo();
</script>

结果是2 函数的作用域取决于声明时 不是调用时

计数器

<script>
  window.cnt=0
    function inc() {
        cnt++;
    }
    inc();
  inc();
  console.log(cnt);
</script>
<script>
    var cnt=100;
    inc();
    console.log(cnt);
</script>

结果是 2 101 会污染变量

<script>
    function counter(){
        var cnt=0;
        var cont =function(){
            return ++cnt;
        }
        return cont;
    }
    var inc =counter();
  console.log(inc());
</script>
<script>
    var cnt=100;
    inc();
    console.log(inc())
</script>

结果是1 3 没有污染变量

<script>
    function counter(){
        var cnt=0;
        return function(){
            return ++cnt;
        }
    }
    var inc =counter();
  console.log(inc());
</script>
<script>
    var cnt=100;
    inc();
    console.log(inc())
</script>

简化版本

<script>
   var inc = (function (){
        var cnt=0;
        return function(){
            return ++cnt;
        }
    })();
    var inc =counter();
  console.log(inc());
</script>
<script>
    var cnt=100;//如果继续var inc =100;又会污染变量
    inc();
    console.log(inc())
</script>

解决变量污染

<script>
    var juce ={};
    juce.inc = (function (){
        var cnt=0;
        return function(){
            return ++cnt;
        }
    })();
  console.log(juce.inc());
</script>
<script>
    var cnt=100;
    inc();
    console.log(inc())
</script>

js的命名空间 别人不能用里面的函数

for循环中的闭包

方法一:通过自定义属性

<script>
   var inp= document.getElementsByTagName("input");
   for (var i=0;i<inp.length;i++){
       inp[i].i=i;
       inp[i].onclick = function () {
           inp[this.i].style.backgroundColor = "red";
       }
   }
   console.log(i);
</script>

方法二:使用let

<script>
   var inp= document.getElementsByTagName("input");
   for (let i=0;i<inp.length;i++){
       inp[i].onclick = function () {
           inp[i].style.backgroundColor = "red";
       }
   }
   console.log(i);
</script>

第三种:使用this 第四种:for循环每执行一次 都会立即执行一个匿名函数 并且匿名函数的作用域中 传入了当时的i

for (var i=0;i<inp.length;i++){
       (function(i){
           inp[i].onclick = function () {
               inp[i].style.backgroundColor = "red";
           }})(i);
   }

第五种:将变量传进作用域

for (var i=0;i<inp.length;i++){
       (function(){
           var arg = i;
           inp[arg].onclick = function () {
               inp[arg].style.backgroundColor = "red";
           }})();
   }

第六种:循环时候立即执行函数 将变量传进作用域

for (var i=0;i<inp.length;i++){
           inp[i].onclick = function (i) {
               return function() {
                   inp[i].style.backgroundColor = "red";
               }
           }(i);
   }

方法七:基本包装类型 通过 new 使用 Function 的构造函数 创建 Function 实例实现,由于传入的函数体的内容是字符串,故 Function 得到的是一个字符串拷贝,而没有得到 i 的引用(这里是先获取 i.toString()然后与前后字符串拼接成一个新的字符串,Function 对其进行反向解析成 JS 代码)

for(var i=0;i<inp.length;i++){
    inp[i].onclick = new Function(`inp[${i}].style.backgroundColor = "red";`);
}

方法九:

function fn(a) {
     alert(1);
 }
 console.log(fn.length);

结果是1,length是形参个数

for (var i=0;i<inp.length;i++){
       (inp[i].onclick = function () {
                   inp[arguments.callee.i].style.backgroundColor = "red";
           }).i=i;//arguments 参数对象  arguments.callee 参数对象所属函数
   }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章