zoukankan      html  css  js  c++  java
  • 一篇文章把你带入到JavaScript中的闭包与高级函数

    file

    在JavaScript中,函数是一等公民。JavaScript是一门面向对象的编程语言,但是同时也有很多函数式编程的特性,如Lambda表达式,闭包,高阶函数等,函数式编程时一种编程范式。

    function dada() {
     var a = 1;
     var b = function() {
      console.log(a);
     }
     return b 
     // b 就是一个闭包函数,因为它能访问dada函数的作用域
    }

    JavaScript的函数也是对象,可以有属性,可以赋值给一个变量,可以放在数组里作为元素,可以作为其他对象的属性,什么都可以做,别的对象能做的它也能做,别的对象不能做的它也能做。

    函数和其他普通对象来说,是一样的,有属性有方法,普通对象能做的,函数也能做。学习JavaScript中的闭包和高级函数是基础篇哦!

    那么什么是闭包?闭包,就是有权访问其外部作用域中的变量和参数的函数。

    var func = (function() {
     var item = 0;
     return {
      add: function(num) {
       item  = typeof num === 'number' ? num : 1;
      },
      value: function() {
       return item;
      }
     }
    })();

    闭包函数可以访问它创建时所处的上下文环境中的变量以及参数,this以及arguments除外。

    闭包:

    函数作为返回值,高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。闭包的形成与变量的作用于和变量的生命周期密切相关。

    变量作用域:

    var func = function() {
     var a = 1;
     console.log(a); // 1
    }
    func();
    console.log(a); // Uncaught ReferenceError: a is not defined

    闭包是一个可以访问到其他函数内部变量的函数,闭包的重点在于,变量的作用域,和,变量的生命周期。

    变量的作用域

    // 变量的作用域
    var my = function() {
     var a = 1;
     console.log('my', a); // 1
    }
    my();
    console.log(a) // ReferenceError: a is not defined

    变量的声明周期

    // 变量的生命周期
    let fu = function() {
     let a = 0;
     a  ;
     console.log('dada', a);
    }
    fu(); // 1
    fu(); // 1
    fu(); // 1
    
    let func = function() {
     let a = 0;
     return function() {
      a  ;
      console.log('a', a);
     }
    }
    
    let fun = func()
    
    fun(); // 1
    fun(); // 2
    fun(); // 3

    闭包中的变量没有被销毁,这个涉及到垃圾回收机制,即标记清楚和引用计数

    function num() {
     for(var i=0; i< 10; i  ) {
      setTimeout(function() {
       console.log('da', i) // 10
      },0)
     }
    }
    num();
    
    function num1() {
     for(var i=0; i< 10; i  ) {
      (function (i) {
       setTimeout(function() {
        console.log('da', i)
       },0)
      })(i) // 1,2,3,...,10
     }
    }
    num1()
    

    什么是闭包的例子:

    function da() {
     var a = 1;
     function dada() {
      console.log(a);
     }
     return dada
    }
    
    var d = da();
    d(); // 1

    闭包如果不是那么必要,请不要去创建它,因闭包在处理速度和内存消耗方面对性能具有负面影响。

    闭包的形式与变量的作用域以及变量的生存周期有着密切的相关性。

    变量的作用域:

    变量的作用域指的是变量的有效范围,当一个函数中声明的一个变量不带上关键字var的时候,这个变量就成为了全局变量,当这个变量用var声明的时候,这个变量就变成了局部变量,只有在函数内部才能访问到这个变量,在函数外面是访问不到的。举例:

    var func = function() {
     var a = 1;
     alert(a); // 1
    };
    func();
    alert(a); // Uncaught ReferenceError: a is not defined

    嵌套例子:

    var a = 1;
    var fun = function() {
     var b = 2;
     var func1 = function() {
      var c = 3;
      alert(b); // 2
      alert(a); // 1
     }
     func1();
     alert(c); // c is not defined
    };
    fun();

    变量的生命周期:

    闭包的又一重要概念,变量的生命周期,对于全局变量的生命周期来说是永久的,对于函数内部的局部变量来说,是短暂的,它们都会随着调用的结束而被销毁。

    var func = function() {
     var a = 1;
    };
    func();
    var func = function() {
     var a = 1;
     return function() {
      a  ;
      alert(a);
     }
    };
    var da = func();
    da(); // 2
    da(); // 3
    da(); // 4

    闭包

    函数作为返回值

    function num(arr) {
     return arr.reduce(function (x,y) {
      return x   y;
     });
    }
    num([1,2,3]); // 6

    变成函数

    function func(arr) {
     var sum = function() {
      return arr.reduce(function(x,y) {
       return x   y;
      });
     }
     return sum;
    }
    
    // 调用 函数
    var da = func([1,2,3]); // 调用函数
    
    // 运行
    da(); // 6
    

    var da1 = func([1,2]);
    var da2 = func([1,2]);
    da1 == da2 // false

    每次调用返回的都是一个新的函数

    利用闭包进行缓存:

    function add(a) {
     return a   1;
    }

    利用闭包进行缓存:

    filefile

    闭包的作用

    封装变量,闭包可以封装形成私有变量:

    var da = function() {
     var a = 1;
     for (var i=0; i < arguments.length; i  ){
      a = a * arguments[i];
     }
     return a;
    }
    alert(a(1,2,3));

    在JavaScript中是没有块级作用域的概念的:

    function add() {
     var arr = [ 1,2,3 ];
     for (var i=0; i < arr.length; i  ) {
      alert( arr[i]);
     }
     var i; // 重新声明变量
     alert(i);
    }

    块级作用域效果,闭包:

    (function() {
     // 块级作用域
    })()

    延续局部变量的生命周期:

    var myImg = function( src ) {
     var img = new Image(0;
     img.src = src;
    };
    myImg('http:///...');

    解决请求丢失问题:

    var da = (function() {
     var imgs = [];
     return function(src) {
      var img = new Image();
      imgs.push(img);
      img.src = src;
     }
    })();

    闭包是指有权访问另一个函数作用域中变量的函数。

    闭包:函数对象可以通过作用域关联起来,函数体内的变量都可以保存在函数作用域内。

    词法作用域:作用域是在编写代码的时候确定的动态作用域:作用域是在代码运行的时候确定的

    <script>
    function add(num){
        var sum = 5;
        return sum   num;
    }
    var sum = add(4);
    </script>
    Execution Contexts = {
        variable object:变量对象;
        this value: this指针;
        scope chain:作用域链;
    }

    全局变量

    function myFunction() {
        var a = 4;
        return a * a;
    }
    var a = 4;
    function myFunction() {
        return a * a;
    }

    var counter = 0;
     
    function add() {
       return counter  = 1;
    }
     
    add();
    add();
    add();
     
    // 计数器现在为 3

    function add() {
        var counter = 0;
        return counter  = 1;
    }
     
    add();
    add();
    add();
     
    // 本意是想输出 3, 但事与愿违,输出的都是 1 !
    function outter(){
      var sky="blue";
      function inner(){
        console.log(sky);
      }
      return inner;
    }
    
    var result=outter();
    result();    //"blue"

    函数与对其状态即为词法环境的引用共同构成闭包,也就是,闭包可以让你从内部函数访问外部函数作用域。

    词法作用域:

    function init() {
        var name = "dada"; 
        // name 是一个被 init 创建的局部变量
        function displayName() { 
        // displayName() 是内部函数,一个闭包
            alert(name); 
            // 使用了父函数中声明的变量
        }
        displayName();
    }
    init();

    闭包:

    function mFunc() {
        var name = "dada";
        function displayName() {
            alert(name);
        }
        return displayName;
    }
    
    var myFunc = mFunc();
    myFunc();

    高阶函数

    什么是高阶函数,JavaScript中的函数都指向某个变量,既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,就叫高阶函数。

    高级函数:

    function add(x, y, f) {
        return f(x)   f(y);
    }

    file

    'use strict';
    
    function pow(x) {
        return x * x;
    }
    
    var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    var results = arr.map(pow); 
    // [1, 4, 9, 16, 25, 36, 49, 64, 81]
    console.log(results);

    var f = function (x) {
        return x * x;
    };
    
    var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    var result = [];
    for (var i=0; i<arr.length; i  ) {
        result.push(f(arr[i]));
    }

    var arr = [1, 3, 5, 7, 9];
    arr.reduce(function (x, y) {
        return x   y;
    }); 
    // 25
    var arr = [1, 3, 5, 7, 9];
    arr.reduce(function (x, y) {
        return x * 10   y;
    }); 
    // 13579

    在一个数组中,删除偶数,保留奇数:

    var arr = [1, 2, 4, 5, 6, 9, 10, 15];
    var r = arr.filter(function (x) {
        return x % 2 !== 0;
    });
    r; 
    // [1, 5, 9, 15]

    回调函数

    var arr = ['A', 'B', 'C'];
    var r = arr.filter(function (element, index, self) {
        console.log(element); 
        // 依次打印'A', 'B', 'C'
        console.log(index); 
        // 依次打印0, 1, 2
        console.log(self); 
        // self就是变量arr
        return true;
    });
    'use strict';
    
    var arr = [10, 20, 1, 2];

    arr.sort(function (x, y) {
        if (x < y) {
            return -1;
        }
        if (x > y) {
            return 1;
        }
        return 0;
    });
    console.log(arr); 
    // [1, 2, 10, 20]

    var a1 = ['B', 'A', 'C'];
    var a2 = a1.sort();
    a1; 
    // ['A', 'B', 'C']
    a2; 
    // ['A', 'B', 'C']
    
    a1 === a2; 
    // true, a1和a2是同一对象

    every()方法可以判断数组的所有元素是否满足测试条件

    find()方法用于查找符合条件的第一个元素

    findIndex()方法返回这个元素的索引

    高阶函数即为输入参数里有函数,或是输出是函数的函数

    function add() {
        var num = 0
        return function(a) {
            return num = num   a
        }
    }
    var adder = add()
    
    adder(1)     
    // 输出: 1
    adder(2)     
    // 输出: 3

    高阶函数满足条件:函数作为参数被传递,函数作为返回值输出

    回调函数:

    var getUserInfo = function( userId, callback ){
        $.ajax( 'http://xxx.com/getUserInfo?'   userId, function( data ){
            if ( typeof callback === 'function' ){
                callback( data );
            }
        });
    }
    getUserInfo( 522624714, function( data ){
        alert ( data.userName );
    });

    //从小到大排列
    [ 1, 5, 3 ].sort( function( a, b ){
        return a - b;
    });
    // 输出: [ 1, 3, 5 ]
    
    //从大到小排列
    [ 1, 5, 3 ].sort( function( a, b ){
        return b - a;
    });
    // 输出: [ 5, 3, 1 ]

    什么是函数式编程,函数式编程时一种编程形式,让你能将函数作为参数传递给其他函数并且能够将函数作为值返回。

    在JavaScript中,函数是一类特殊的对象:

    function hello() {
     console.log('hello');
    }
    hello();
    hello.name='da';
    
    console.log(hello.name); // da
    const num = function(x) {
     return x*x;
    }
    
    num(8); // 64

    高阶函数是一个函数,它是接收函数作为参数或者是将函数作为输出的值进行返回。高阶函数实战:

    const arr1 = [1,2,3];
    const arr2 = arr1.map(function(x) {
     return x * 2;
    });
    console.log(arr2);
    const arr1 = [1,2,3];
    const arr2 = arr1.map(x => x*2);

    结语

    简而言之,高阶函数是一个函数,它是可以接受函数作为参数,还可以作为返回一个值返回,返回一个函数。闭包可以让你从内部函数访问外部函数作用域。闭包即是一个函数,能够访问另一个函数作用域的变量的函数。

    关于目前文章内容即涉及前端,PHP知识点,如果有兴趣即可关注,很荣幸,能被您发现,真是慧眼识英!也感谢您的关注,在未来的日子里,希望能够一直默默的支持我,我也会努力写出更多优秀的作品。我们一起成长,从零基础学编程,将 Web前端领域、数据结构与算法、网络原理等通俗易懂的呈现给小伙伴。分享 Web 前端相关的技术文章、工具资源、精选课程、热点资讯。

    推荐阅读

    1、你知道多少this,new,bind,call,apply?那我告诉你

    2、为什么学习JavaScript设计模式,因为它是核心

    意见反馈:若本号内容有做得不到位的地方(比如:涉及版权或其他问题),请及时联系我们进行整改即可,会在第一时间进行处理。

    感谢阅读,原创不易,喜欢就点个赞吧,这是我写作最大的动力。

    欢迎关注达达的简书!

    这是一个有质量,有态度的博客

    博客

  • 相关阅读:
    zz[读书笔记]《Interpretable Machine Learning》
    Xgboost,LightGBM 和 CatBoost
    zz:Xgboost 导读和实战
    bzoj3252: 攻略 优先队列 并查集 贪心
    [BeiJing2009 WinterCamp]取石子游戏 Nim SG 函数
    Playing With Stones UVALive
    Division Game UVA
    [BJWC2011]禁忌 AC 自动机 概率与期望
    [Jsoi2010]连通数 bitset + Floyd
    洛谷P2197 nim游戏模板
  • 原文地址:https://www.cnblogs.com/dashucoding/p/11932259.html
Copyright © 2011-2022 走看看