资讯专栏INFORMATION COLUMN

闭包的学习与总结

YanceyOfficial / 1407人阅读

摘要:第一部分执行代码之后,返回了一个新的匿名函数,此时在全局作用域调用匿名函数它不在是的属性或者方法,此时调用者是因此输出是。总结关于中的,记住谁调用,就指向谁要访问闭包的,要定义个变量缓存下来。

前言:
这是一篇关于闭包函数的总结和笔记

希望对大家有点帮助
写的不好的地方,也请大家多多指教

一: js中的命名函数,匿名函数,自调用函数和回调函数
1.命名函数: 函数如果有名字,就是命名函数

function f1( ) {
            console.log("我就是命名函数");
        }

2.匿名函数: 函数如果没有名字,就是匿名函数

(function () {
            console.log("我就是匿名函数");
        })   

3.自调用函数: 自己调用自己

var f2 = function () {
            console.log("你好");
        };
        f2();

fn里面存储的是函数体代码,通过fn()的方式调用. 匿名函数自调用: 在匿名函数后面加括号,里面外面都可以; 也可以在函数前用 ! + -;
原因:js只能识别表达式(由运算符组成的式子) 与 语句( 程序流程控制 );让匿名函数可以调用原理:将匿名函数变成表达式

4.回调函数: 回调函数就是一个参数将这个函数作为参数传到另一个函数里面当那个函数执行完之后,再执行传进去的这个函数。

function f3(fn) {
            fn();  //函数调用 --- 说明fn这个变量中存储的是一个函数
        };
        function f4() {
            console.log("函数可以作为参数使用")
        }
        f3(f4);   // 调用f3,将f4作为参数使用        

二: 函数的语法
1.函数声明

 function f5() {
            console.log("我是函数声明");
        };
        f5()

2.表达式声明

var f6 = function () {
        console.log("我是表达式声明");
    };
    f6();

三: 匿名函数的四种常见场景
1.注册事件

 document.querySelector("#btn").onclick = function () {
            console.log("我是匿名函数调用的一种场景");
        };

2.定时器

setInterval(function () {
            console.log("我是定时器中的匿名函数");
        },1000);

3.变量存储

 var f7 = function () {
            console.log("我是变量存储中的函数");
        };

4.对象方法

var obj = {
            name: "拉克丝",
            say: function () {
                console.log(this.name);
            }
        };
        obj.say();

四: 闭包函数
闭包有三个特性: 函数嵌套函数; 函数内部可以引用外部的参数和变量; 参数和变量不会被垃圾回收机制回收
闭包的好处是:1.希望一个变量长期驻扎在内存中 2.避免全局变量的污染 3.私有成员的存在

01 全局变量的累加

 var a = 1;
        function f7( ){
            a++;
            alert(a);
        }

        f7();    // 2
        f7();    // 3
        f7();    // 4

02 局部变量

function f8( ){
            var a = 1;
            a++;
            alert(a);
        }
 
        f8();  // 2
        f8();  // 2
        f8();  // 2

03 局部变量的累加

 function outer( ){
            var x = 10;
            return function ( ) {
                //函数嵌套函数
                x++;
                alert(x);
              }
        }

        //外部函数只调用一次,得到的同一个变量
        var y = outer();   //外部函数赋值给变量y  调用一次外部函数,得到一个闭包函数
        y();      // 11    //调用闭包函数,返回内部变量
        y();      // 12
        y();      // 13
        
        outer()();  // 11
        outer()();  // 11
        outer()();  // 11

04 经典例子

function fn() {
            var num = 3;
            return function () {
                var n = 0;
                console.log(++n);
                console.log(++num);
            }
        }
        var fn1 = fn();   
        fn1()   // 1   4
        fn1()   // 1   5
        fn1()   // 1   6
        
        fn()()  // 1   4
        fn()()  // 1   4
        fn()()  // 1   4

05 模块化代码,减少全局变量的污染

var abc = (function ( ) {
            //abc 为外部匿名函数的返回值
            var a = 1;
            return function ( ) {
                a++;
                alert(a);
              }
        }());
        abc();   // 2  // 调用一次abc函数,其实就是调用里面内部函数的返回值
        abc();   // 3
        abc()    // 4

06 私有成员的存在

 var aaa = (function ( ) {
            var a = 1;
            function bbb( ) {
                a++;
                alert(a);
            }
            function ccc( ) {
                a++;
                alert(a);
            }
            return {
                b: bbb,   
                c: ccc
            }
        })();

          aaa.b();  // 2
          aaa.c();  // 3
          aaa.b();  // 4
          aaa.c();  // 5

07 使用匿名函数实现累加
使用匿名函数实现局部变量驻留在内存中,从而实现累加

function aaa( ) {
            var a = 10;
            return function ( ) {  //匿名函数
            a++;
            return a;
            };
        }

        var y = aaa();
        alert(y());   //  11
        alert(y());  //   12
        alert(y());  //   13

08 闭包作为参数传递

        var num = 15;
        var fn1 = function (x) {
            if(x > num){
                console.log( x );
            }
        }
        void function (fn2) {
            var num = 100;
            fn2(30);
        }(fn1);   // 30
        // void  相当于匿名函数的自调用
        // fn2是当做参数传进来的  不是在void里面声明的  是在全局作用域里声明的 所以拿的是num=15   所以打印出来30

对上题有疑惑的,可以看下面这个

 var num = 15;
        var fn1 = function (x) {
            if(x > num){
                console.log( x );   // 30
            }
        }
        void function (fn2) {
            var num = 100;
            fn2(30);
            function fn3(x) {
                console.log( num );  // 100
                if(x < num){
                    console.log( x );  //30
                }
            }
            fn3(30)
        }(fn1);   

闭包的应用场景
一.点击li标签,出现对应的索引

  • 你好我是循环闭包中的第0个
  • 你好我是循环闭包中的第1个
  • 你好我是循环闭包中的第2个
  • 你好我是循环闭包中的第3个
  • 你好我是循环闭包中的第4个

1.js中添加索引的做法

 var ul1 = document.getElementById("ul1");
        for(var i = 0; i < ul1.children.length; i++){
            ul1.children[i].setAttribute("index",i);
            ul1.children[i].onclick = function () {
                console.log(this.getAttribute("index"))
            }
        };

2.jQuery中index做法

  $(function () {
            var index = null;
            $("li").on("click",function () {
                index = $(this).index();
                console.log(index);
            });
        })

3.闭包的处理

     var ul1 = document.getElementById("ul1");
        //错误的做法
        function showLiNum(ul1) {
            for(var i = 0; i < ul1.children.length; i++){
                ul1.children[i].onclick = function () {
                    console.log(i);
                }
            }
        }
        showLiNum(ul1)
        //当点击之前,循环已结束;所以i的值为别.children.length;

正解:利用一个闭包,建立一个匿名函数;将每个i存在内存中.onclick函数用的时候提取出外部匿名函数的值

  function showLiNum(ul1) {
            for(var i = 0; i < ul1.children.length; i++){
              (function (i) {
                  ul1.children[i].onclick = function () {
                      console.log(i);
                  }
              }(i));
            }
        }
        showLiNum(ul1)

也可以这样

  function showLiNum(ul1) {
            for(var i = 0; i < ul1.children.length; i++){
                ul1.children[i].onclick = (function (i) {
                    return function () {
                        console.log(i);
                    }
                }(i));
            }
        }
        showLiNum(ul1);

二.定时器
开启定时器,分别打印1,2,3,4,5

错误的写法:

        for(var i = 1; i <= 5; i++){
            setTimeout(function () {
                console.log(i);
            },1000)
        }

正确写法

 for(var i = 1; i <= 5; i++){
            (function (i) {
                setTimeout(function () {
                    console.log(i);
                },i*1000);
            }(i))
        }
        //相当于同时启动3个定时器,i*1000是为5个定时器分别设置了不同的时间,同时启动,
        //但是执行时间不同,每个定时器间隔都是1000毫秒,实现了每隔1000毫秒就执行一次打印的效果。

经典面试题
最后上一道闭包中的经典面试题,如果你能弄懂这个,那说明闭包弄懂的差不多啦

 var name = "The Window";
        var obj = {
            name : "The object",
            getNameFunc : function(){
                return function(){
                    return this.name;
                }
            }
        }
        alert( obj. getNameFunc()() )  

        var name = "The Window";
        var obj = {
            name : "The object",
            getNameFunc : function(){
                var that = this;
                return function(){
                    return that.name;
                }
            }
        }
        alert( obj. getNameFunc()() )           

javascript是动态(或者动态类型)语言,this关键字在执行的时候才能确定是谁。所以this永远指向调用者,即对"调用对象"的引用; "谁调用,指向谁"。
第一部分执行代码object.getNameFunc()之后,返回了一个新的匿名函数,此时在全局作用域调用匿名函数,它不在是object的属性或者方法,此时调用者是window,因此输出是 The Window。
第二部分,当执行函数object.getNameFunc()后返回的是:function( ){return that.name;}此时的that=this。而this指向object,所以that指向object。他是对object的引用,所以输出The Object。
总结:关于js中的this,记住谁调用,this就指向谁;要访问闭包的this,要定义个变量缓存下来。一般var that(_this) = this。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/102888.html

相关文章

  • 通过示例学习JavaScript闭包

    摘要:译者按在上一篇博客,我们通过实现一个计数器,了解了如何使用闭包,这篇博客将提供一些代码示例,帮助大家理解闭包。然而,如果通过代码示例去理解闭包,则简单很多。不过,将闭包简单地看做局部变量,理解起来会更加简单。 - 译者按: 在上一篇博客,我们通过实现一个计数器,了解了如何使用闭包(Closure),这篇博客将提供一些代码示例,帮助大家理解闭包。 原文: JavaScript Clos...

    xingpingz 评论0 收藏0
  • JavaScript - 收藏集 - 掘金

    摘要:插件开发前端掘金作者原文地址译者插件是为应用添加全局功能的一种强大而且简单的方式。提供了与使用掌控异步前端掘金教你使用在行代码内优雅的实现文件分片断点续传。 Vue.js 插件开发 - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins译者:jeneser Vue.js插件是为应用添加全局功能的一种强大而且简单的方式。插....

    izhuhaodev 评论0 收藏0
  • JS笔记

    摘要:从最开始的到封装后的都在试图解决异步编程过程中的问题。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。异步编程入门的全称是前端经典面试题从输入到页面加载发生了什么这是一篇开发的科普类文章,涉及到优化等多个方面。 TypeScript 入门教程 从 JavaScript 程序员的角度总结思考,循序渐进的理解 TypeScript。 网络基础知识之 HTTP 协议 详细介绍 HTT...

    rottengeek 评论0 收藏0
  • JS框架 - 收藏集 - 掘金

    摘要:现在回过头总结,才又进一步的揭开了闭包的一层后台管理系统解决方案前端掘金基于系列的后台管理系统解决方案。什么是继承大多数人使用继承不外乎是为了获得基于的单页应用项目模板前端掘金小贴士本项目已升级至。 关于js、jq零碎知识点 - 掘金写在前面: 本文都是我目前学到的一些比较零碎的知识点,也是相对偏一点的知识,这是第二篇。前后可能没有太大的相关性,需要的朋友可以过来参考下,喜欢的可以点个...

    wenyiweb 评论0 收藏0
  • Python

    摘要:最近看前端都展开了几场而我大知乎最热语言还没有相关。有关书籍的介绍,大部分截取自是官方介绍。但从开始,标准库为我们提供了模块,它提供了和两个类,实现了对和的进一步抽象,对编写线程池进程池提供了直接的支持。 《流畅的python》阅读笔记 《流畅的python》是一本适合python进阶的书, 里面介绍的基本都是高级的python用法. 对于初学python的人来说, 基础大概也就够用了...

    dailybird 评论0 收藏0

发表评论

0条评论

YanceyOfficial

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<