闭包和匿名函数

阻止事件冒泡

方法一:

  • 事件对象中的stopPropagation()函数可以阻止事件冒泡
  • 阻止事件冒泡方法,在阻止对象的前一级阻止
<div><span>选择班级</span>
<ul>
    <li>一班</li>
    <li>二班</li>
    <li>一班</li>
    <li>二班</li>
    <li>一班</li>
    <li>二班</li>
    <li>一班</li>
    <li>二班</li>
</ul>
</div>
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<btns.length;n++){
        btns[n].onclick =function(){
            console.log(n+1); //4,4,4
                }
    }

  • 案例解析:全部变成4,函数内部的代码是consoel.log,函数内部没有变量n,for里面有一个变量n,且n的3时,for循坏是3时结束了。绑定完事件,当n变成3,才触发事件,此时n就是3
  • 需要的是绑定事件的那一刻的n
  • 方法一:
for(var n = 0;n<btns.length;n++){
        btns[n].index=n+1;//将123放在三个函数里面
        btns[n].onclick =function(){
            console.log(this.index); //将值放在事件的属性上
        };
    }

方法二:

for(var n = 0;n<btns.length;n++){ //匿名自执行函数
        (function (a){
            btns[a].onclick =function(){
            console.log(a+1); //btns事件函数就是闭包,因为btns是全局的按钮
        }
        })(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);}("我是大商股份?"); //我是大商股份?
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352

推荐阅读更多精彩内容