JS函数的应用 --- 立即执行函数全局污染闭包沙箱递归

Posted zxvictory

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS函数的应用 --- 立即执行函数全局污染闭包沙箱递归相关的知识,希望对你有一定的参考价值。

一、立即执行函数 --- IIFE

  • 立即执行函数的集中表现形式:

  • 立即执行函数的特点:

二、JS 全局污染

为什么会造成全局污染?

  • JS 没有块级作用域,在函数外定义的变量,均为全局变量;

  • 全局变量过多会削弱程序的灵活性,增大了模块之间的耦合度,多人协作开发会导致变量冲突,造成环境污染。

    • 耦合度:即模块之间的依赖关系:控制关系、调用关系、数据传递关系;
    • 划分模块准则:高内聚低耦合

如何解决全局污染?

1. 命名空间
2. 立即执行函数(里面创建的变量,为局部变量)
(function(){})()
(function(){}())
!function(){}()
var fn = function(){} ()

三、闭包

1. 闭包的概念

  • 广义闭包:函数内部声明变量,函数外部无法访问到,模拟块级作用域,即生成闭包
    • JS 中所有函数,都能形成一个闭包
  • 狭义闭包:闭包模型(一个函数,作为另一个函数的返回值)

  • 闭包实际上由两部分组成:
    • 函数体:函数的代码
    • 函数所处的环境:作用域链
  • 综上:把函数体 及 函数所处的环境,成为闭包

2. 主线:函数 不管在哪个环境下调用,都要回到创建函数的环境下执行

3. 闭包作用:

  • 解决全局污染

  • 对函数内的变量,起保护作用;除了返回函数外,没有任何办法可以访问到函数内的变量

4. 经典闭包模型

  • 可简单理解为,一个函数作为另一个函数的返回值;这样就有了内层函数,和外层函数;

  • 外层函数中:定义变量(对变量起保护作用)

  • 返回值返回的 内层函数:定义操作变量的方法

  • 闭包模型如下:

<script>
    var fn = function() {
        var num = 10;
        
        return {
            f1: function() {}
            f2: function() {}
        }
    };
    
    var temp = fn();
    
    // 调用 f1 、f2 方法
    temp.f1();
    temp.f2();
</script>

4. 闭包弊端(内存泄露)---> 解决:内层函数 = null

  • 闭包中外层函数定义的变量一直存在,不会被自动释放掉;

  • 因为内层函数一直引用着 外层函数中定义的变量;并且内层函数每一次操作变量,都是在外层函数中变量基础上进行操作的

  • 手动释放内存占用内层函数 = null

四、沙箱(闭包的一种体现形式)

1. 沙箱模式

  • 函数自调用

  • 给window注册属性 或 return 变量

  • 经典沙箱模式如下:

<script>
(function(window) {
    // 定义变量,及一些列js逻辑
    var main = ‘‘;

    window.main = main;return main;
})(window)
</script>
  • jQuery中运用沙箱模式,如下:
(function() {
    
    window.jQuery = window.$ = jQuery;
    return jQuery;
})();

2. 沙箱的作用:

  • 变量隔离,保护变量(沙箱内定义的变量,沙箱外不能访问到)

  • 避免全局污染

3. IIFE 立即执行函数

(function(){})()
(function(){}())
!function(){}()
var fn = function(){} ()

五、函数 递归

1. 简单理解递归:函数自己 ---> 调用自己

2. 何时用递归:函数需要多次调用自己,自己嵌套自己

3. 如何书写 递归函数(3点)?

    1. 划归思想:找出规律,总结前者 、 后者之间的关系
    1. 临界条件:找出临界值,停止递归
    1. retrun 自己函数的调用

4. 递归相关算法实现:

  • 递归实现兔子数列(菲波那切数列)
<script>
    function fn3(m) {
        if (m === 1 || m === 2) {
            return 1;
        }

        return fn3(m-1) + fn3(m-2);
    }

    console.log(fn3(20));
</script>
  • 菲波那切数列 优化【缓存】
<script>
    var cache = {};

    function fn4(m) {
        if (cache[m]) {
            return cache[m];
        }

        if (m === 1 || m === 2) {
            cache[m] = 1;
            return 1;
        } else {
            return cache[m] = fn4(m-1) + fn4(m-2);
        }
    }

    console.log(fn4(200));
</script>
  • 递归:阶乘
<script>
    function fn2(m) {
        if (m <= 1) {
            return 1;
        }

        return fn2(m-1) * m;
    }

    console.log(fn2(3));
</script>
  • 递归:次方
<script> 
    function fn1(m, n) {
        if (n === 0) {
            return 1;
        }
        
        return fn1(m, n -1) * m;
    }
    
    console.log(fn1(2,4));
</script>

5. 严格模式下,递归 ---> 健壮代码

  • 非严格模式下,简易递归
<script>
    var fn = function (m) {
        if (m <= 1) {
            return 1;
        }

        return fn(m-1) * m;
    }

    var fn1 = fn;
    fn = null;

    console.log(fn1(3));  // 报错
</script>
  • 非严格模式下,健壮递归

    • arguments.callee 指向一个正在执行的函数的指针
<script>
    var fn = function (m) {
        if (m <= 1) {
            return 1;
        }

        return arguments.callee(m-1) * m;
    }

    var fn1 = fn;
    fn = null;

    console.log(fn1(3));  // 6
</script>
  • 严格模式下,不允许用 arguments.callee, 健壮代码如下:
<script>
    var fn1 = function fn(m) {
        if (m <= 1) {
            return 1;
        }

        return fn(m-1) * m;
    }

    var fn2 = fn1;
    fn1 = null;

    console.log(fn2(3));
</script>

以上是关于JS函数的应用 --- 立即执行函数全局污染闭包沙箱递归的主要内容,如果未能解决你的问题,请参考以下文章

JS中闭包的作用

闭包的高级使用-变量私有化-模块化开发-js命名空间

初识模块化

箭头函数和立即执行函数

js-闭包

javascript闭包和立即执行函数的作用