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>

原文地址:https://www.cnblogs.com/zxvictory/p/8267127.html

时间: 2024-12-26 21:09:32

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

lua 根据函数名字符串来执行函数

function myfunction(msg) print("this is msg fun " .. msg); end local fun =_G["myfunction"]; if fun then fun("is ok"); end lua 根据函数名字符串来执行函数

JS自调用函数问题(立即执行函数)

第一个问题 function ( ) { console.log("fun1"); }() 为什么执行不了? . “函数使用function关键字来定义,可以使用函数定义表达式或者函数声明语句.两种形式中,函数定义都是从function关键字开始.其后跟随:函数名称标识符(函数名称是函数声明语句必需的部分:对于函数定义表达式来说,这个名字是可选的:如果存在,该名字只存在于函数体中,并指代该函数对象本身).”—摘自<JavaScript权威指南> 1.使用function声明

第10天:apply和call、bind、函数作为参数、返回值使用、闭包、递归的样例

apply和call apply和call都可以改变this的指向 函数的调用,改变this的指向 函数名字.apply(对象,[参数1,参数2,.....]) 方法名字.apply(对象,[参数1,参数2,.....]) 方法名字.call(对象,参数1,参数2,.....) 方法名字.call(对象,参数1,参数2,.....) 不同的地方:参数传递是方式不一样 只要是想使用别的对象的方法,并且希望这个方法是当前对象的,那么久可以使用apply或者call的方法改变this的指向 apply

jquery中ready函数,$(function(){})与自执行函数的区别

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <script type="text/javascript" src="js/jquery-1.12.1.js"></script> <script type=&q

学习js函数--自执行函数

我在写代码时候经常会在tpl的<script>里写类似的代码: $(function(){ alert("我好饿"); }); 刚开始的时候只知道写了它不需要调用,直接执行,就这样依葫芦画瓢,我写了很多代码.说道这,还要说说这货的加载顺序,如果把代码直接写到script标签里,当页面加载完这个script标签就会执行里边的代码了.如果在这代码里用到了未加载的dom或者调用了未加载的方法,是会报错的.言归正传,这个函数其实就是自执行函数,很多人会比较专业地称为"立即

JS执行顺序-函数声明提升、匿名函数、函数表达式

大方向上: JS 是按照 代码块 进行 编译.执行 的. 学习至: 1.变量声明提升 2.新唐的博客 3.js中匿名函数的创建与调用方法分析 4.前端圣经 - 高程三 5.深入理解变量声明提升和函数声明提升 因为没有好好地分类.可能会比较杂.为了系统地学习,先了解几个概念. 一. <script> 区分的代码块. JS是按照代码块 编译 和 执行的.代码块间 相互独立,但是 变量和方法 共享. <script> alert('代码块一'); </script> <

JS 自执行函数

由于自己js基础知识薄弱,很多js的知识还没有掌握,所以接下来会经常写一些关于js基础知识的博客,也算给自己提个醒吧. js自执行函数,听到这个名字,首先会联想到函数.接下来,我来定义一个函数: function aaa(a,b){ return sum = a + b } 定义了一个名为aaa的函数,在里面可以计算两个数的和.如果想执行它,就必须得调用它,并且还得给它传参: var aa = aaa(1,2) 这样就实现了一个函数的定义与调用,通过console.log我们可以看到sum实现了

js 立即执行函数

1.我们首先要搞明白:函数表达式和函数声明的区别. 函数表达式:既可以为匿名函数也可以有函数名,但是调用的时候都是通过函数左边的变量func来调用 var func = function(){ alert('xxx'); }; var b = new func(); 函数声明:必须有函数名 function func(){ alert('xxx'); } func(); 所以立即执行调用的函数表达式有一下几种 !function () { /* code */ } ();~function ()

js自执行函数表达式

// 下面2个括弧()都会立即执行 (function () { /* code */ } ()); // 推荐使用这个(function () { /* code */ })(); // 但是这个也是可以用的 和普通function执行的时候传参数一样,自执行的函数表达式也可以这么传参,因为闭包直接可以引用传入的这些参数,利用这些被lock住的传入参数,自执行函数表达式可以有效地保存状态. // 这个代码是错误的,因为变量i从来就没背locked住// 相反,当循环执行以后,我们在点击的时候i