闭包的使用一些总结

2023-11-08

我们看一下官方对于闭包的解释,走起

	闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建。
	自己的工作角度理解:闭包是一个函数,另外就是他是函数内的函数,他有需求,想要访问外部的作用域,那到底工作中怎么用呢?我用几个小例子给大家模拟一下

第一个小例子 我们想要打印一下一个变量调用值–情况

var a = 10;
        function fn(){
            a--;
            console.log(a)
        }

在这里插入图片描述
注释:有没有发现我在图片中打岔的地方,跟大家说一下原因,因为我声明的是全局变量,所以造成了在浏览器控制台任何人都可以控制我的变量,这个是老板不喜欢的,所以你懂得!!!

那么我们把全局变量放在函数中中不?

function fn(){
            var a = 10;
            a--;
            console.log(a)
        }

在这里插入图片描述
解释:这时候我们发现控制台不能被控制我的a变量,但是我们发现业务逻辑没有了,没有实现–情况,大家想一想,你的函数是不是一直都是调用的a=9,有人会说那不应该一直是8吗,因为流程是自上往下的,所以一直都是9,是一个自上往下的过程,大家要记清楚。

那我们再试试下边的情况

function fn(){
            var a = 10;
            return function fn1(){
                a--;
                console.log(a)
            }
        }
        var niu = fn()

在这里插入图片描述
解释:我们会发现 业务需求达到了,老板的目的也达到了,在工作中我们经常用闭包。

总结 闭包要素有哪些???

1.是一个嵌套函数;
2.嵌套函数中内部函数要访问外部函数的变量;
3.内部函数作为一个返回值供使用
4.创建一个变量函数去接着这个闭包,让其使用

这时候我们明白闭包可以防止全局变量环境污染,但是单独的局部变量不能长期驻足,所以我们发现第二种情况函数用完销毁,重新用重新赋值,那么我们闭包这种机制就完美解决这个问题,让我们长期保留(不会在调用结束后,被垃圾回收机制回收)也能够不造成全局变量的环境污染。

世界上没有完美的事情,因为闭包会占更多的内存,因为她属于Function,会消耗更多的内存空间。

下边我再说一下工作中我们在哪些常见的场景使用闭包?

第一个 setTimeout()

function func(param){
        return function(){
            alert(param)
        }
        }
        let fn = func('1');
        setTimeout(fn,1000)

第二个 回调

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title></title>
    <link rel="stylesheet" href="">
</head>
<style>
    body{
        font-size: 12px;
    }
    h1{
        font-size: 1.5rem;
    }
    h2{
        font-size: 1.2rem;
    }
</style>
<body>

    <p>哈哈哈哈哈哈</p>
    <h1>hhhhhhhhh</h1>
    <h2>qqqqqqqqq</h2>

    <a href="#" id="red">red</a>
    <a href="#" id="blue">blue</a>
    <a href="#" id="yellow">yellow</a>

<script>
    function changeSize(color){
        return function(){
            document.body.style.color = color;
        };
    }

    var red = changeSize('red');
    var blue = changeSize('blue');
    var yellow = changeSize('yellow');

    document.getElementById('red').onclick = red;
    document.getElementById('blue').onclick = blue;
    document.getElementById('yellow').onclick = yellow;
    //我们定义行为,然后把它关联到某个用户事件上(点击或者按键)。我们的代码通常会作为一个回调(事件触发时调用的函数)绑定到事件上
</script>
</body>
</html>

第三个封装一个私有变量

//共享的环境创建在一个匿名函数体内,立即执行。
    //环境中有一个局部变量一个局部函数,通过匿名函数返回的对象的三个公共函数访问。
    var a = (function(){
        let b = 0;
        function niu(val){
            b += val;
        };
        return {
            jiaYi:function(){
                niu(1)
            },
            jianYi:function(){
                niu(-1)
            },
            value:function(){
                return b
            }
        }
    })()
    a.value();//0
    a.jiaYi();
    console.log(a.value())//1
    a.jianYi();
    console.log(a.value())//0

为节点遍历给事件

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<link rel="stylesheet" href="">
</head>
<body>

<p id="info">123</p>
<p>E-mail: <input type="text" id="email" name="email"></p>
<p>Name: <input type="text" id="name" name="name"></p>
<p>Age: <input type="text" id="age" name="age"></p>

<script>
function showContent(content){
    document.getElementById('info').innerHTML = content;
};

function setContent(){
    var infoArr = [
        {'id':'email','content':'your email address'},
        {'id':'name','content':'your name'},
        {'id':'age','content':'your age'}
    ];
    for (var i = 0; i < infoArr.length; i++) {
        var item = infoArr[i];
        document.getElementById(item.id).onfocus = function(){
            showContent(item.content)
        }
    }
}
setContent()

</script>
</body>
</html>


上述代码原本想实现,点击不同的框显示不同的信息,结果现在都只会显示最后一项“your age”

分析:

循环中创建了三个闭包,他们使用了相同的词法环境item,item.content是变化的变量
当onfocus执行时,item.content才确定,此时循环已经结束,三个闭包共享的item已经指向数组最后一项。
解决:

/**
 * 解决方法1     通过函数工厂,则函数为每一个回调都创建一个新的词法环境
 */
function showContent(content){
    document.getElementById('info').innerHTML = content;
};

function callBack(content){
    return function(){
        showContent(content)
    }
};

function setContent(){
    var infoArr = [
        {'id':'email','content':'your email address'},
        {'id':'name','content':'your name'},
        {'id':'age','content':'your age'}
    ];
    for (var i = 0; i < infoArr.length; i++) {
        var item = infoArr[i];
        document.getElementById(item.id).onfocus = callBack(item.content)
    }
}
setContent()

/**
 * 解决方法2        绑定事件放在立即执行函数中
 */
function showContent(content){
    document.getElementById('info').innerHTML = content;
};

function setContent(){
    var infoArr = [
        {'id':'email','content':'your email address'},
        {'id':'name','content':'your name'},
        {'id':'age','content':'your age'}
    ];
    for (var i = 0; i < infoArr.length; i++) {
        (function(){
            var item = infoArr[i];
            document.getElementById(item.id).onfocus = function(){
                showContent(item.content)
            }
        })()//放立即执行函数,立即绑定,用每次的值绑定到事件上,而不是循环结束的值
    }
}
setContent()

/**
 * 解决方案3        用ES6声明,避免声明提前,作用域只在当前块内
 */
function showContent(content){
    document.getElementById('info').innerHTML = content;
};

function setContent(){
    var infoArr = [
        {'id':'email','content':'your email address'},
        {'id':'name','content':'your name'},
        {'id':'age','content':'your age'}
    ];
    for (var i = 0; i < infoArr.length; i++) {
        let item = infoArr[i];      //限制作用域只在当前块内
        document.getElementById(item.id).onfocus = function(){
            showContent(item.content)
        }
    }
}
setContent()

喜欢的老铁们,点个赞吧!!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

闭包的使用一些总结 的相关文章

  • Imgur API 版本 3 JavaScript 上传示例

    我在网上找到的所有示例都是早期版本的 Imgur API 或非 JS 代码 所有这些都使用新 API 中不存在的 API 密钥 相反 你会得到一个client id and secret 任何人都有示例代码 展示如何使用其 API 版本 3
  • 获取画布上下文的最后一个点的坐标

    我想创建一个arrowTo功能与CanvasRenderingContext2D prototype 为此 我需要获取最后一个点的坐标 例如 var ctx someCanvas getContext 2d ctx moveTo 10 40
  • onclick 函数上的 CSS 选择器

    有没有办法让CSS选择器onclick function 您可以在onclick https stackoverflow com questions 24365416 select element which have specific a
  • 将 Laravel 集合/数组转换为 Javascript 数组

    我想将 Laravel 中的数组分配给 JavaScript 数组 我已经从我的AppServiceProvider和 json decoded 它像 View composer function view users Users all
  • 循环内的局部变量会被垃圾收集吗?

    我想知道将循环内引用的任何变量放在循环外是否更有效 或者它们可以像函数内的变量一样被垃圾收集吗 var obj key val for var i 0 i lt 10 i console log obj or for var i 0 i l
  • 使用画布元素作为文本区域

    我正在寻找有关如何使用类似于文本区域的画布元素的直接描述 我见过这样的项目Ace http ace ajax org 只是想知道如何像文本区域一样写入该区域 只是纯文本 没有什么花哨的 提前致谢 Ace 曾经是 Mozilla Skywri
  • 在 HTML5 中使用 JS 创建内联 SVG

    我正在使用本地 HTML5 文件 它有在顶部 我在里面放了这样的东西
  • 向 JS 计算器添加键盘支持时出现的问题

    我想为我的计算器添加键盘支持 当我用键盘按下操作 即 或 时 js将其视为数字 而不是操作 例如 当我通过点击计算 10 11 时 我将得到 21 作为结果 当我通过键盘输入时 我会得到 10 为什么会发生这种情况 是否可以改变它 div
  • Sails.js - 如何更新嵌套模型

    attributes username type email validated by the ORM required true password type string required true profile firstname s
  • Visual Studio IDE 中功能后的空间

    如何设置 Visual Studio 中的设计以在我的 javascript 函数后面放置一个空格 目前 当我按下返回键时 我得到了这个 var myfunc function 当我想要这个的时候 var myfunc function 知
  • Disqus 评论数始终为 0 条评论

    我想我已经按照通用代码的说明设置了 Disqus 问题是它总是说某个帖子有 0 条评论 拿这个帖子来说 http tx0rx0 com retropie and the raspberry pi http tx0rx0 com retrop
  • Vue Draggable - 如何仅替换所选项目以防止移动网格上的所有其他项目?

    这是一个要测试的示例 https codesandbox io s j4vn761455 file src App vue 112 116 https codesandbox io s j4vn761455 file src App vue
  • SVG 中三角形的圆角

    我正在尝试制作一个具有圆角的三角形 三角形将如下所示 左下角是唯一看起来相当容易制作的角 主要是因为这是一个 90 度的 转弯 该转弯是使用QSVG 中的命令具有以下参数 Q x y height x y height RADIUS从我正在
  • 使用 Javascript eval() 100% 安全吗?

    我正在编写一个生成 Javascript 代码的 PHP 库 Javascript 代码有许多名为component001 component002 etc 页面通过 AJAX 动态加载 我需要通过 URL 变量传递组件的名称 然后由脚本进
  • 将数组中的所有元素相乘

    我在这里找不到我真正想要的例子 我想将所有数组元素相乘 因此如果数组包含 1 2 3 总和将为 123 6 到目前为止 我已经得到了这段代码 但它返回未定义 function multiply array var sum 1 for var
  • 使用 Socket.IO 时如何访问会话标识符?

    我有一个聊天 我需要管理独特的连接 我四处搜寻 但我找到的解决方案似乎都已被弃用 那么 如何使用 Socket IO 获取套接字的会话 ID 我在用着Node js http en wikipedia org wiki Node js Ex
  • 在多个数组中搜索字符串,然后设置 var - jQuery

    我正在寻找基于字符串存在于哪个数组中设置一个变量 例如 var primary red blue yellow var secondary orange purple green 然后检查 purple 并返回它在 secondary 数组
  • 当选项卡重新加载(chrome 扩展)时,如何运行此脚本?

    所以我想在指定 URL 中重新加载选项卡时运行脚本 它几乎可以工作 但实际上 id 不能 这是我的清单文件 manifest version 2 name Sample Extension description Sample Chrome
  • 如何仅突出显示嵌套表的最里面的表行?

    我有几个嵌套表 我想突出显示鼠标指针下方的最里面的行 我怎样才能做到这一点 一些提示 我使用嵌套表来显示递归表格数据 表可以嵌套 10 层 嵌套正如您所期望的那样 table tr td table tr td table tr td 可能
  • ES6 Reflect API 的好处

    我一直在努力升级一些代码以使用 ES6 语法 我有以下代码行 delete this foo 我的 linter 提出了使用建议 Reflect deleteProperty this foo 您可以找到该方法的文档here https d

随机推荐