在JavaScript中闭包的作用和简单的用法

一、闭包的简介

作用域链:在js中只有函数有作用域的概念,由于函数内能访问函数外部的数据,而函数外部不能访问函数内部的数据,由上述形成一种作用域访问的链式结构叫做作用域链。

闭包:通过某种方式实现的一个封闭的、包裹的对外不公开的结构|空间,有人称之为封闭空间,以及匿名函数自调。闭包可以使函数外部访问函数内部的数据。

、闭包的基本写法

1、通过return来访问函数内部的变量

(function(){var a = 10; return 变量 | 函数 });

2、通过立即执行函数访问函数内部的变量

01、(function(){})();  // 常用

02、(function(){}());  // 常用

03、;function(){}();

04、+function(){}();

05、-function(){}();

、闭包的作用

1、闭包的作用

01、提供一种间接访问函数内部变量的方法

02、延长函数内部的局部变量的生命周期(慎用!局部变量过多会占大量内存)

03、全局变量私有化,减少全局变量污染

04、函数局部变量在函数执行完后释放内存(函数执行完毕,其内部的变量立即销毁)

05、更新复杂变量(可以对变量进行校验和判断,保证安全性和稳定性)

2、代码示例

01、提供一种间接访问函数内部变量的方法

function A() {
    var num = 10;// 局部变量
    return num;// 访问内部数据
}
var B1 = A();
console.log(B1);// 10   说明局部变量没有销毁   延长函数内部的局部变量的生命周期

上述代码可以在外部访问函数A内部的局部变量,并延长局部变量num的生命周期,但也有缺陷,每次访问都是一次性的,无法修改保存其变量如下代码所示:

function foo() {
    var obj = {
        name:"张三",
        age:28
    };
    return obj;
}
var obj1 = foo();
var obj2 = foo();
console.log(obj1 == obj2);  //false

上述代码所示两次访问的对象不是同一个`console.log(obj1 == obj2); // false`!

03、全局变量私有化,减少全局变量污染

(function () {
    window.onload = function () {// 全局变量私有化
        
    };
})();

(function () {
    var d = document;
    var btn1 = d.getElementById('btn');
    var btn2 = d.getElementById('btn');
    var btn3 = d.getElementById('btn');
})();

05、更新复杂变量(可以对变量进行校验和判断,保证安全性和稳定性)

001、设置数据

function test() {
    var str1 = '字符串1';
    return function (str) {
        str1 = str; // 设置数据
        return str1;
    }
}
var test1 = test();
console.log(test1('hello')); // hello
console.log(test1()); // undefined

上述代码是设置数据,但并没有判断数据,由于函数调用时没有传参,所以结果是`console.log(test1()); // undefined`,我们还可以在其内部添加校验和判断,代码如下:

function test() {
    var str1 = '字符串1';
    return function (str) {
        if(typeof str == 'string'){// 判断传参是不是string类型
            str1 = str; // 设置数据
        }
        return str1;
    }
}
var test1 = test();
console.log(test1('hello')); // hello
console.log(test1()); // undefined

002、返回多个数据

以数组的形式返回

function person() {
    var name = "黄忠";
    var age = 45;
    return [function () {//以数组的形式返回多个数据
        return name;
    },
        function () {
            return age;
        }];
}
var p1 = person();
console.log(p1[0]()); // 黄忠
console.log(p1[1]()); // 45

一般不怎么以数组的形式返回数据!

以对象的形式返回

function person() {
    var name = "黄忠";
    var age = 45;
    return {
        getName:function () {//以对象的形式返回多个数据
            return name;
        },
        getAge:function () {
            return age;
        }
    }
}
var p1 = person();
console.log(p1.getName()); // 黄忠
console.log(p1.getAge()); // 45

我们一般以这种形式返回多个数据!

003、以对象形式返回多个数据并设置多个数据

function person() {
    var name = "黄忠";
    var age = 45;
    return {
        getName:function () {//以对象的形式返回多个数据
            return name;
        },
        getAge:function () {
            return age;
        },
        setName:function (value) {
            //容错性处理 + 逻辑校验
            //判断
            if (typeof value != 'string')
            {
                throw "该函数只接受字符串类型的参数";
            }
            name = value;
        },
        setAge:function (num) {
            //容错性处理 + 逻辑校验
            //判断
            //console.log(num == NaN);// false
            var str = String(num);// 把获取的实参转为字符串
            var str1 = String(NaN);// 把NaN转为字符串
            if ((str == str1) || typeof num != 'number' )
            {//判断输入的是否为数字类型并且不为NaN
                throw "该函数只接受数字类型的参数并且不为NaN";
            }
            age = num;
        }
    }
}
var p1 = person();
console.log(p1.getName()); // 黄忠
console.log(p1.getAge()); // 45
p1.setName('郭嘉');// 修改名字
p1.setAge(28);// 修改年龄
console.log(p1.getName()); // 郭嘉
console.log(p1.getAge()); // 28

上述代码在返回的对象中多添加了setName方法和setAge方法,并在方法内部做了容错处理和校验判断,这样使代码的安全性和稳定性更好!

## 四、闭包的应用场景

1、for循环中

For循环中,for循环执行的速率非常快,有时候,我们希望保存变量i,用于其他地方。我们就可以用到闭包!代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<button>第一个</button>
<button>第二个</button>
<button>第三个</button>
<button>第四个</button>
<button>第五个</button>
<script>
    var btns = document.getElementsByTagName('button');
    //遍历按钮
    for(var i= 0;i < btns.length;i++){
        (function (a) {// 保存在形参中
            btns[a].onclick = function () {// 按钮点击事件  每点击对应的按钮弹出对应的数字
                alert(a+1);
            }
        })(i) ;// 把i当作实参传进去
    }
    console.log(i);// 5 //在js中只有函数有作用域的概念
</script>
</body>
</html>

但上述代码中变量i是全局变量会影响其他的for循环,我们也可以用闭包把for循环包起来,防止全局变量污染!代码如下:

var btns = document.getElementsByTagName('button');
//遍历按钮
(function () {
    for(var i= 0;i < btns.length;i++){
        (function (a) {// 保存在形参中
            btns[a].onclick = function () {// 按钮点击事件  每点击对应的按钮弹出对应的数字
                alert(a+1);
            }
        })(i) ;// 把i当作实参传进去
    }
})();
console.log(i);// Uncaught ReferenceError: i is not defined // i 未定义

上述代码把for循环包起来,就把全局变量私有化了,外面就无法访问了,所以报错未定义。

2、在for循环中处理事件机制时我们经常用到闭包!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<button>第一个</button>
<button>第二个</button>
<button>第三个</button>
<button>第四个</button>
<button>第五个</button>
<script>
    var btns = document.getElementsByTagName('button');
    //遍历按钮
    for(var i= 0;i < btns.length;i++){
        btns[i].onclick = (function (a) {
            return function () {
                alert(a+1);
            }
        })(i);
    }
</script>
</body>
</html>

3、在定时器中使用闭包

for (var i = 0; i < 10; i++) {
    setTimeout((function (j) {
        return function () {
            console.log(j);
        }
    })(i),1000);
}

结论

闭包的原理:变量的访问原则(即上一级的作用域无法访问下一级的作用域),其实函数本身就是闭包

六、源码链接

https://github.com/350469960/OS/blob/master/javascript/closure.md

在JavaScript中闭包的作用和简单的用法的更多相关文章

  1. javascript中闭包最简单的简绍

    javascript中闭包是什么 JavaScript 变量可以是局部变量或全局变量.私有变量可以用到闭包.闭包就是将函数内部和函数外部连接起来的一座桥梁. 函数的闭包使用场景:比如我们想要一个函数来 ...

  2. 在Javascript中闭包(Closure)

    在Javascript中闭包(Closure) 什么是闭包 “官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. ...

  3. javascript中defer的作用

    javascript中defer的作用 <script src="../CGI-bin/delscript.js" defer></script>中的def ...

  4. JavaScript中常见的字符串操作函数及用法

    JavaScript中常见的字符串操作函数及用法 最近几次参加前端实习生招聘的笔试,发现很多笔试题都会考到字符串的处理,比方说去哪儿网笔试题.淘宝的笔试题等.如果你经常参加笔试或者也是一个过来人,相信 ...

  5. JavaScript中常见的数组操作函数及用法

    JavaScript中常见的数组操作函数及用法 昨天写了个帖子,汇总了下常见的JavaScript中的字符串操作函数及用法.今天正好有时间,也去把JavaScript中常见的数组操作函数及用法总结一下 ...

  6. 博文推荐】Javascript中bind、call、apply函数用法

    [博文推荐]Javascript中bind.call.apply函数用法 2015-03-02 09:22 菜鸟浮出水 51CTO博客 字号:T | T 最近一直在用 js 写游戏服务器,我也接触 j ...

  7. JavaScript中闭包的写法和作用详解

    1.什么是闭包 闭包是有权访问另一个函数作用域的变量的函数. 简单的说,Javascript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内.而且,这些内部函数可以访问它们所在的外 ...

  8. javascript中闭包的概念

    这个是每个前端工程师绕不开的一个问题,网上各种资料很多,整个春节,我仔细研读了红皮经典中关于这一块的注释,加深了对这一块的理解. 有好几个概念需要重申一下.以下都是我的理解: 1. 闭包是javasc ...

  9. Javascript中闭包的个人理解

       Javascript的一个特殊点就在于它的闭包和回调特性,这两个特性让初学Javascript的我是云里雾里,至今仍在苦苦摸索与理解.在一番苦思之后,整理了一下资料,将自己的理解思路记录下来,以 ...

随机推荐

  1. novell.directory.ldap获取邮箱活动目录

    在windows系统上可以使用下列方法来查找所有的员工邮箱和员工组: StringDictionary ReturnArray = new StringDictionary(); Dictionary ...

  2. DedeCMS 列表页调用图集内容多张图片的方法

    新做一个以图片为主的网站,采用的DEDECMS图集,列表页要求直接调内容面的大图,解决方法如下:(主要是采用php的正则匹配函数preg_match_all函数来巩固复习下该函数:preg_match ...

  3. 【转】如何利用多核CPU来加速你的Linux命令 — awk, sed, bzip2, grep, wc等

    如何利用多核CPU来加速你的Linux命令 — awk, sed, bzip2, grep, wc等   你是否曾经有过要计算一个非常大的数据(几百GB)的需求?或在里面搜索,或其它操作——一些无法并 ...

  4. oracle12安装软件后安装数据库,然后需要自己配置监听

    oracle12安装软件后安装数据库,然后需要自己配置监听 没想到你是这样的oracle12: 不能同时安装软件和数据库,分别安装之后,\NETWORD\ADMIN\下面竟然没有listener.or ...

  5. MySQL具体解释(14)----------事务处理

    前言:前一篇文章关于事务处理的博文没有写清楚,读起来非常晦涩.非常难理解,所以有整理了一些资料,帮助理解.见谅! 关于MySQL事务处理学习记 START TRANSACTION COMMIT ROL ...

  6. IP、操作系统、移动OS

    IP IP地址 = 网络地址 + 主机地址/IP地址 = 网络地址 + 子网地址 + 主机地址. DNS :进行域名解析的服务器.             比如,sina.com(是域名).其实是一个 ...

  7. C语言之基本算法32—鞍点

    //数组 /* ================================================================== 题目:求随意矩阵的全部鞍点.并统计个数.(在矩阵中 ...

  8. 策略模式(headfirst设计模式学习笔记)

    鸭子的行为被封装 进入一组类中,能够轻易的扩展和改变.假设须要能够执行时改变行为! 策略模式定义了算法族.分别封装起来.让他们能够相互替换,此模式让算法的变化独立于使用算法的客户. 继承,相似之处用继 ...

  9. Node.js学习笔记(6)——使用Express创建一个工程

    前提是搭建好了环境,node,npm,express:(推荐全局安装) 开始用express创建一个基础工程: express –t ejs microblog 进入文件夹之后 npm-install ...

  10. 设置windows时间开机同步方法

    本作品由Man_华创作,采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可.基于http://www.cnblogs.com/manhua/上的作品创作. 适用场景: 主板电池 ...