闭包和匿名函数

阻止事件冒泡

方法一:

  • 事件对象中的stopPropagation()函数可以阻止事件冒泡
  • 阻止事件冒泡方法,在阻止对象的前一级阻止
选择班级
  • 一班
  • 二班
  • 一班
  • 二班
  • 一班
  • 二班
  • 一班
  • 二班
document.getElementsByTagName("div")[0].onclick=function(){ document.getElementsByTagName("ul")[0].style.display="block"; } //绑定班级选择事件 document.getElementsByTagName("ul")[0].onclick=function(e){ e =e||window.event; var target=e.target; document.getElementsByTagName("span")[0].innerText =target.innerText; //隐藏班级列表 document.getElementsByTagName("ul")[0].style.display="none"; e.stopPropagation(); };

方法二:使用将cancelBubble属性设置为true阻止冒泡,默认值是false,表示允许冒泡

  • 在早期ie版本中并不支持stopPropagation,而是使用将cancelkBubble属性设置为true阻止冒泡
        document.getElementsByTagName("ul")[0].style.display="none";
        // e.stopPropagation();
        e.cancelBubble = true;
    };

取消事件默认行为

  • 有些时候页面元素的默认行为需要阻止
  1. 事件对象的preventDefault函数阻止默认行为
  2. 使用return false
//为回到顶部绑定js事件
    document.getElementsByTagName("a")[0].onclick=function(e){ //事件的响应比默认行为块,才能在事件中阻止默认行为,形参相当于局部变量,不需要声明
        e = e||window.event;
        // console.log(document.body.scrollTop);
        // e.preventDefault();

        return false;
    };

匿名自执行函数

创建匿名函数后,该函数立即执行。

  1. 用括号括起来,告诉函数这是一个整体
(function(str){
        console.log(str); //用括号括起来,告诉函数这是一个整体
    })("我没有名字");
  1. 加括号,让解释器把这个当成独立的整体
(function (str){
            console.log(str);
        }("我是雷锋")); //加括号,让解释器把这个当成独立的整体
  1. 借用逻辑运算符+-!~
!function(str){ //比较常用!

            console.log(str);
        }("你是谁")
        ~function(str){

            console.log(str);
        }("你是谁4")
        +function(str){

            console.log(str);
        }("你是谁+")
        -function(str){

            console.log(str);
        }("你是谁-")

其他让匿名函数执行的方式

var fn = function(str){ //左侧是变量,右侧匿名函数,两个创建,靠变量执行,依赖了变量
        return str;
        }("变量");
        console.log(fn);
        console.log(typeof [function(str){ console.log(str);}("我是大商股份?")]);//我是大商股份?

//匿名函数借用数组,函数返回值赋值给数组下标为0 的值

[][0]=function(str){ console.log(str);}("我是大商股份?"); //我是大商股份?

函数高级应用场景

  • 函数在js中被称作一等公民
  • 函数作为参数
var interval = setInterval(function(){
        console.log(1111);
        clearInterval(interval);
    },1000);
  • 函数内部嵌套函数
function outer(){; //作用域链,右下到上
        var a =100,b = 200; 
        function inner(){
            return a+b;
        }
        var c =inner();
        return c;
    }
    var d = outer();
    console.log(d);
  • 函数作为另一个函数的返回值
function fn(){
        return function(){
            console.log("我是被返回的函数!")
        };
    }
    fn();
    var f1 =fn(); //返回的是函数
    f1();//在调用函数

闭包

  • 闭包:是被外层函数返回的,使用外层函数变量的一个内部函数。
  • 闭包功能:通过外层函数开创独立的命名空间,内部代码不会污染外部空间(不会干扰外部),而外部代码也不能破坏内部作用域中的变量和数据
  • 闭包滥用带来的问题:由于闭包持有的上层作用域在闭包有效的状态下,也必须一直有效,所有滥用闭包会导致大量内存空间被长期占用而不被释放,可能导致性能缓慢,甚至内存泄漏(内存中空间持续占用,不被释放,为内存泄漏。
  • 正常情况下,局部变量会被销毁,在这里num会随着函数执行会被增加,闭包就是提供了为全局使用内部作用域中内容的途径。封闭空间中提供了一个访问的通道
  • 当闭包不需要再使用时,可以释放闭包
  • bib=null;
var num=200;
        return function(){
            num+=50;
            console.log(num);
        };
    }
    var bib = outer(); //返回一个函数,有一个全局变量作用函数,里面的返回函数不能被销毁,这个函数用的变量也会保持长期有效
    bib();
    //如果不用讲全局变量设置的值为bib=null;
     console.log(num);
     //当闭包不需要再使用时,可以释放闭包
     // bib=null;
// var num=300;
    function outer(){
        var num = 200;
        return function(){
            num+=50;
        console.log(num); //250
        };
    }
    var bib = outer();
    bib();//250
    bib(); //300

21点游戏案例

//创建一个21点游戏函数
var counter = (function (){
        var total =0;
        return function(num){
            total+=num;
            if(total>21){
                total=0;
                console.log("loser,回家去!");
            }else if(total==21){
                total=0;
                console.log("算你运气好!");
            }else{
                console.log("加油!!");
            }
        };
     })();
     // var counter = count21();
     counter(18); //加油
     counter(3);//算你运气好
  • 主意:在函数内部用var声明是局部变量,如果没写var,表示全局变量,不建议使用,不规范
  1. 将内层函数提供给全局作用域的方式,并不只局限于return
  • 方法一:使用闭包模拟一个常量,全大写的只有缩写(HTML,JSON)或者变量不允许修改,可以使用,叫做常量
  • 变量声明时如果不使用 var 关键字,那么它就是一个全局变量,即便它在函数内定义

变量生命周期

  • 全局变量的作用域是全局性的,即在整个JavaScript程序中,全局变量处处都在。
  • 而在函数内部声明的变量,只在函数内部起作用。这些变量是局部变量,作用域是局部性的;函数的参数也是局部性的,只在函数内部起作用。

JavaScript 内嵌函数

  • 所有函数都能访问全局变量。
  • 实际上,在 JavaScript 中,所有函数都能访问它们上一层的作用域。
  • JavaScript 支持嵌套函数。嵌套函数可以访问上一层的函数变量。
  • 该实例中,内嵌函数 plus() 可以访问父函数的 counter 变量
var getVersion =(function(){
        var version = "10086"; 
        return function(newVersion){ 
            return version = newVersion; //一次返回多个参数,需要一个容器,用对象装
        };
      })();
      console.log(typeof getVersion); //function
      console.log(getVersion()); //10086
      //为version提供修改功能

      //数据封装,封装参数
      var confUtil=(function(){
        var conf ={
            version:10086,
            size:"xxl",
            date:"2017809"
        };
        return {
            getPro:function(proName){ //获取名字
                return conf[proName]; //返回拿到的对象
            },
            setPro:function(proName,proValue){
                conf[proName]=proValue;
            },
            delPro:function(proName){
                delete conf[proName];
            }
        }; //返回装着很多函数的对象
      })();
      
      console.log(confUtil); //包含三个函数的对象
        console.log(confUtil.getPro("size"));//xxl
        console.log(confUtil["getPro"]("size")); //xxl
        console.log(confUtil.setPro("size","xxxxl"));//修改size里面的值xxxxl
        console.log(confUtil["setPro"]("size","xxxxl"));
        console.log(confUtil.delPro("data")); //undefined
        console.log(confUtil.view()); //Object {version: 10086, size: "xxxxl"}

js为什么要传window?

  • 引用数据类型传的是地址,将window传入,它自身有window并且地址直接指向全局中的window,不需要通过找到外层函数,再去找window那么函数会直接找到window,可以优化代码
(function(w){
            var version = "10086"; 
            w.getVersion=function(){ 
                return version ; 
                    };
          })(window);

for典型案例

绑定事件(3个按钮点击事件)

var btns = document.getElementsByTagName("input");
    for(var n = 0;n
  • 案例解析:全部变成4,函数内部的代码是consoel.log,函数内部没有变量n,for里面有一个变量n,且n的3时,for循坏是3时结束了。绑定完事件,当n变成3,才触发事件,此时n就是3
  • 需要的是绑定事件的那一刻的n
  • 方法一:
for(var n = 0;n

方法二:

for(var n = 0;n
  • console.log(n); //for循坏里面的n,也是全局变量
  • for里面有3个函数,有3个独立的模块
  • 自动触发
for(var n = 0;n<3;n++){ //setTimeout,独立的,for执行结束此时n为3,
        (function(n){ 
            setTimeout(function(){ //等了就变成最后的值
            console.log(n);
        },1000); 
        })(n);
        // setTimeout(function(n){ //等了就变成最后的值
        //  console.log(n);
        // },1000); //输出3个值,都是3 ,解决方案,外层套一个匿名自执行函数
        // console.log(n); //0,1,2
    }

匿名自执行函数的方式有3种

  • 匿名自执行函数,创建匿名函数后,该函数立即执行。
  1. 用括号括起来,告诉函数这是一个整体
;(function(str){
        console.log(str); //用括号括起来,告诉函数这是一个整体
    })("我没有名字");
  1. 加括号,让解释器把这个当成独立的整体
(function (str){
            console.log(str);
        }("我是雷锋"));
  1. 借用逻辑运算符+-!~
!function(str){ //比较常用!

            console.log(str);
        }("你是谁")
        ~function(str){

            console.log(str);
        }("你是谁4")
        +function(str){

            console.log(str);
        }("你是谁+")
        -function(str){

            console.log(str);
        }("你是谁-")

匿名函数的功能

  • 匿名自执行函数最突出的功能,开辟类似块级作用域的独立命名空间。内部变量不会对外部产生污染,将各个非全局功能模块封装在独立命名中,可以有效的避免相互干扰。

其他让匿名函数执行的方式

var fn = function(str){ //左侧是变量,右侧匿名函数,两个创建,靠变量执行,依赖了变量
        return str;
        }("变量");
        console.log(fn);
        console.log(typeof [function(str){ console.log(str);}("我是大商股份?")]);//我是大商股份?
        //匿名函数借用数组,函数返回值赋值给数组下标为0 的值
        [][0]=function(str){ console.log(str);}("我是大商股份?"); //我是大商股份?

你可能感兴趣的:(闭包和匿名函数)