js闭包

需求:点击某个按钮,提示点击的是第n个按钮

    var btns=document.getElementsByTagName('button');
    for(var i=0;i<btns.length;i++){
        var btn=btns[i];
        btn.onclick=function () {
            alert('点击'+(i+1)+'个');
        }
    }

  运行上面的代码,i始终是btns.length+1

改进:

   var btns=document.getElementsByTagName('button');
    for(var i=0;i<btns.length;i++){
        (function (i) {
            var btn=btns[i];
            btn.onclick=function () {
                alert('点击'+(i+1)+'个');
            }
        })(i);
    }

  如何产生闭包:

当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包.

使用chrome调试查看

 

 

 理解一:闭包是嵌套的内部函数

理解二:包含被引用变量(函数)的对象

注意:闭包存在于嵌套的内部函数中

常见的闭包使用形式:

1.将函数作为另一个函数的返回值

  

function  fn1() {
    var num=10;
    function fn2(){
        num++;
        console.log(num);
    }
    return fn2;
}
var f=fn1();
f();//11
f();//12

  

 

2.将函数的形参作为实参传递给另一个函数调用.

//大的函数中包含小的函数,小函数中引入了大函数的变量,就形成了闭包
function logMsgDelay(msg,time) {
    setTimeout(function () {
        console.log(msg);
    },time);
}
logMsgDelay('老石',1000);

  

 

 

 

function myTool(){
    var money=1000;
    //提供操作私有函数的操作
    function get(){
        money*=10;
        console.log('总资产:'+money+'元');
    }
    function send(){
        money--;
        console.log('花了一笔钱,总资产:'+money+'元');
    }
    return {
        'get':get,
        'send':send
    };
}

  调用:

<script type="text/javascript" src="s/myTool.js"></script>
<script>
   var toolObj= myTool();
   toolObj.get();

</script>

  另一种写法:

(function(w){
   var money=1000;
   function get(){
        money*=10;
        console.log('总资产:'+money+'元');
    };
   function send(){
        money--;
        console.log('花了一笔钱,总资产:'+money+'元');
   }
   w.myTool={
       'get':get,
       'send':send
   }
})(window)

  

 myTool.get();
   myTool.send();

  高级排他:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        li{
            border:1px solid #000;
            background-color: #ccc;
            cursor: pointer;
        }
        .current{
            background-color: orangered;;
        }
    </style>
</head>
<body>
<ul>
    <li class="current"></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
</ul>
<script>

    window.onload = function () {
       var allLis = document.getElementsByTagName('li');
       for(var i=0; i<allLis.length; i++){
           var li = allLis[i];
           li.onmouseover = function () {
               for(var j=0; j<allLis.length; j++){
                    allLis[j].className = '';
               }
               this.className = 'current';
           }
       }
   }

window.onload = function () {
    var allLis = document.getElementsByTagName('li');
    // 记录移动前选中li对应的索引
    var preSelectLiIndex = 0;
    for(var i=0; i<allLis.length; i++){
        (function (i) {
            var li = allLis[i];
            li.onmouseover = function () {
                // 清除
                allLis[preSelectLiIndex].className = '';
                // 设置
                this.className = 'current';
                // 赋值
                preSelectLiIndex = i;
            }
        })(i);
    }
}
</script>
</body>

  实现函数节流:

var timer = null;
      window.onresize = function () {
          clearTimeout(timer);
          timer = setTimeout(function () {
              console.log('输出的内容!!!!');
          }, 200);
      }

  内存泄露:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>02_内存溢出与内存泄露</title>
</head>
<body>

<!--
1. 内存溢出
   一种程序运行出现的错误
   当程序运行需要的内存超过了剩余的内存时, 就抛出内存溢出的错误


2. 内存泄露
   占用的内存没有及时释放
   内存泄露积累多了就容易导致内存溢出
   常见的内存泄露:
    1. 占用内存很大的全局变量
    2. 没有及时清理的计时器/定时器
    3. 闭包
-->

<script type="text/javascript">
    // 1. 内存溢出
   /* var arrObj = {};
    for(var i=0; i<100000000; i++){
        arrObj[i] = new Array(999999);
        console.log(arrObj);
    }*/


   // 2. 常见的内存泄露
    // 占用内存很大的全局变量
   /* var num = new Array(99999999);
    var num1 = new Array(99999999);
    var num2 = new Array(99999999);
    var num3 = new Array(99999999);
    var num4 = new Array(99999999);
    var num5 = new Array(99999999);
    var num6 = new Array(99999999);
    var num7 = new Array(99999999);
    num = null;*/


   // 没有及时清理的计时器/定时器
   /* var intervalId = setInterval(function () {
        console.log("-----");
    }, 1000);
    clearInterval(intervalId);*/

   // 闭包
    function fn1() {
        var num  = 1111;
        function fn2() {
            num--;
            console.log(num);
        }

        return fn2;
    }

    var f = fn1();
    f();

    f = null;
</script>
</body>
</html>

  构造函数设置属性和方法

<script type="text/html">

    // 注意: 以下的属性和方法, 都是绑定在使用构造函数创建出来的对象p上; 最终使用的时候也是使用对象p来进行访问;
    // 我们把这种类型的属性和方法, 称为 实例属性/实例方法
    function Person(name, age, doFunc) {
        this.name = name;
        this.age = age;
        this.doFunc = doFunc;
    }

    var p1 = new Person('sz', 18, function () {
        console.log('sz在上课');
    });
    var p2 = new Person('王二小', 18, function () {
        console.log('王二小在放羊');
    });

    console.log(p1.name);
    console.log(p1.age);
    p1.doFunc();

    console.log(p2.name);
    console.log(p2.age);
    p2.doFunc();
</script>

  

// 静态属性, 静态方法
// 绑定在函数身上, 一定要注意: 函数本质也是一个对象, 既然是个对象, 那么就可以动态的添加属性和方法
// 只要函数存在, 那么绑定在它身上的属性和方法, 也会一直存在
// 想要记录总共创建了多少个人?

function Person(name, age, doFunc) {
        this.name = name;
        this.age = age;
        this.doFunc = doFunc;
        if (!Person.personCount) {
            Person.personCount = 0;
        }
        Person.personCount++;
    }

    Person.printPersonCount = function () {
        console.log('总共创建了'+ Person.personCount + '个人');
    };


    var p1 = new Person('sz', 18, function () {
        console.log('sz在上课');
    });
    var p2 = new Person('王二小', 18, function () {
        console.log('王二小在放羊');
    });

    console.log(p1.name);
    console.log(p1.age);
    p1.doFunc();
    console.log(p2.name);
    console.log(p2.age);
    p2.doFunc();

    Person.printPersonCount();

  

posted @ 2020-04-01 20:53  石shi  阅读(125)  评论(0编辑  收藏  举报