小小千想和您聊一聊

当前位置: 首页> 技术分享> JavaScript中的闭包

JavaScript中的闭包

   JavaScript 本身是一门若类型语言。从其语法设计来看,是一门比较容易上手、容易学习的语言。

   但是,在 Javascript 中也有一些比较难以理解的知识点,其中闭包就是一个。

  1. 词法作用域

   为了更好的理解闭包的概念和应用,首先我们要掌握JavaScript中词法作用域。

   作用域分为 全局作用域 和 局部作用域。

  · 局部作用域:由于函数可以限定作用域范围,因此在函数内部为 局部作用域。

  · 全局作用域:不在任何函数内,而是在整个脚本script标签下,都有效的访问范围被称为 全局作用域。

   请看下面代码:

var a = 10;
function foo(){
    var b = 'hi';
}

foo();

   在上面代码中,变量a 不在任何函数中定义,因此 变量a 为全局变量;而在函数foo中定义的变量b 是 局部变量。变量a 在整个脚本范围内,即script标签下都是可以被访问到的,但是变量b则只能在函数foo内部为访问到。

   那么,问题就来了。“如果在实际开发时,在函数foo外部,也想访问到变量b呢?”。此时,闭包技术就此登场了。

  2. 闭包的概念

  闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

   看下面代码:

// 函数foofunction foo(){
    var a = 10; // 函数内部变量
    // 根据作用域规则,在函数内部可以访问变量a
    // 根据闭包的概念,闭包是一个函数
    // 下面函数可以满足闭包的两个条件:1 可以访问foo中变量a;2 自己本事 是 函数。因此该函数 就是 闭包。
    function closure(){
        // closure函数是可以访问foo中变量a的
        console.log(a + 10);
    }
    
    // 那么 在函数foo外部 如何 通过闭包closure 建立连接呢?
    // 很简单,就是让外部 可以 接收到 闭包的一个引用即可。
    return closure; // 这样 当函数foo调用时,外部就可以接收到闭包了。也就可以通过闭包来获取函数foo内部的变量了
}
var c = foo();// 每次在想要拿到foo内部变量a,就可以通过闭包c了console.log(c);  // 1console.log(c);  // 2

  闭包的基本结构

   从闭包的概念可以看出闭包具有这样的结构:

  · 外部函数

  · 内部函数,并且引用外部函数内的变量

  · 返回内部函数

  3. 闭包的其他形式

  闭包可以在基本的结构中,扩展出一种或多种结构。

// 1 匿名闭包函数function outer(){
    var a = 10;
    // 返回匿名闭包函数
    return function(){
        console.log(a++);
    };
}
// 2 函数形参也算是内部的变量function outer1(n){
    return function(){
        console.log(n);
    };
}
// 3 返回对象(包含闭包)function person(){
    var obj = {
        name: '张三',
        age: 19
    };
    // 对象里边包含三个闭包函数
    return {
        getName: function(){
            return obj.name;
        },
        getAge: function(){
            return obj.age;
        },
        setAge: function(v){
            if(v < 0){
                console.error('非法的年龄值。');
                return;
            }
            obj.age = v;
        }
    }
}

  4. 闭包的应用

  在 Web 中,你想要这样做的情况特别常见。大部分我们所写的 JavaScript 代码都是基于事件的 — 定义某种行为,然后将其添加到用户触发的事件之上(比如点击或者按键)。我们的代码通常作为回调:为响应事件而执行的函数。

  高阶函数

  以下是css:

body {
  font-family: Helvetica, Arial, sans-serif;
  font-size: 12px;
}
h1 {
  font-size: 1.5em;
}
h2 {
  font-size: 1.2em;
}

  我们的文本尺寸调整按钮可以修改 body 元素的 font-size 属性,由于我们使用相对单位,页面中的其它元素也会相应地调整。

  以下是JavaScript:

function makeSizer(size) {
  return function() {
    document.body.style.fontSize = size + 'px';
  };
}
var size12 = makeSizer(12);var size14 = makeSizer(14);var size16 = makeSizer(16);

  size12,size14 和 size16 三个函数将分别把 body 文本调整为 12,14,16 像素。我们可以将它们分别添加到按钮的点击事件上。如下所示:

document.getElementById('size-12').onclick = size12;document.getElementById('size-14').onclick = size14;document.getElementById('size-16').onclick = size16;

  以下是HTML结构:

<a href="#" id="size-12">12</a><a href="#" id="size-14">14</a><a href="#" id="size-16">16</a> 

  私有方法

  编程语言中,比如 Java,是支持将方法声明为私有的,即它们只能被同一个类中的其它方法所调用。

  而 JavaScript 没有这种原生支持,但我们可以使用闭包来模拟私有方法。私有方法不仅仅有利于限制对代码的访问:还提供了管理全局命名空间的强大能力,避免非核心的方法弄乱了代码的公共接口部分。

var Counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }   
})();
console.log(Counter.value()); /* 0 */
Counter.increment();
Counter.increment();console.log(Counter.value()); /* 2 */
Counter.decrement();console.log(Counter.value()); /* 1 */

  5. 闭包的特点

   最后,总结一下。虽然闭包是JavaScript中比较难以理解和运用的一个知识点,但是只要多想、多练、多体会还是可以达到标准的水平的。

   但是,也要考虑一下性能问题。因为闭包的使用会造成内存的开销变大,滥用闭包就很有可能造成内存泄露,同时闭包的使用也会影响处理速度。

上一篇:帮大家理解ES6中的Map

下一篇:HTMLCollection对象和NodeList对象

QQ技术交流群

HTML5/Web前端锋迷群
712051083

加入群聊

用户登录

手机号:

密码:

图形验证码:

点击切换

用户注册

手机号:

登录密码:

图形验证码:

点击切换

短信验证码:

获取验证码

忘记密码

1安全验证

2重置密码

手机号:

图形验证码:

短信验证码:

获取验证码

忘记密码

1安全验证

2重置密码

新密码:

确认新密码:

获取课程

添加小千老师微信,获取课程信息

如何获取课程?

一、需拥有此本教材

如没有,可点击下方入口购买当当购买入口京东购买入口

二、添加小千老师,发送拥有凭证,解锁课程资源

1.购买该教材的订单信息
2.拥有的实体书信息等

更换手机号

新手机号:

图形验证码:

短信验证码:

获取验证码
0.4253s