资讯专栏INFORMATION COLUMN

什么是闭包?

zxhaaa / 2269人阅读

摘要:无论焦点在哪个输入域上,显示的都是关于年龄的消息该问题的原因在于赋给是闭包中的匿名函数而不是闭包对象解决这个问题的一种方案是使指向一个新的闭包对象。

闭包定义 对闭包的具体定义有很多种说法,这些说法大体可以分为两类:

闭包是其词法上下文中引用了自由变量的函数.

闭包是由函数和其相关的引用环境组合而成的实体.

词法:变量的作用域是由它在源码中所处位置决定的.

很多人都觉得闭包是一个很难理解的知识点,其实不然,不管它的定义有多难理解,我们只需自己对它形成一种自己可以理解的定义就可以了,并保证这种自我理解定义的正确性和可行性.

在这里来看,闭包不管他是一个函数还是一个实体,它给我的理解就是一个函数可以访问当前上下文的环境变量.在这样看来,不管是函数内部的函数,还是单个定义的函数,有函数的地方就存在闭包.

闭包的特性和好处 闭包的特性:

函数内部可以引用外部的参数和变量.

参数和变量不会被垃圾回收机制回收.

使用闭包的好处

希望一个变量长期保存在内存中

可以拥有私有成员

在函数内部存在函数形式的闭包中,可以避免全局变量的污染

举例 函数内部函数
function init() {
  var name = "closure";
  function displayName() {
    alert(name);
  }
  displayName();
}
init();

函数 init() 创建了一个局部变量 name,然后定义了名为 displayName() 的函数。 displayName() 是一个内部函数——定义于 init() 之内且仅在该函数体内可用。displayName() 没有任何自己的局部变量,然而它可以访问到外部函数的变量,即可以使用父函数中声明的 name 变量。

用闭包模拟私有方法
var makeCounter = function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }  
};

var Counter1 = makeCounter();
var Counter2 = makeCounter();
alert(Counter1.value()); /* 提示 0 */
Counter1.increment();
Counter1.increment();
alert(Counter1.value()); /* 提示 2 */
Counter1.decrement();
alert(Counter1.value()); /* 提示 1 */
alert(Counter2.value()); /* 提示 0 */

请注意两个计数器是如何维护它们各自的独立性的。每次调用 makeCounter() 函数期间,其环境是不同的。每次调用中, privateCounter 中含有不同的实例。
这种形式的闭包提供了许多通常由面向对象编U所享有的益处,尤其是数据隐藏和封装。

在循环中创建闭包:一个常见错误

Helpful notes will appear here

E-mail:

Name:

Age:

function showHelp(help) {
  document.getElementById("help").innerHTML = help;
}

function setupHelp() {
  var helpText = [
      {"id": "email", "help": "Your e-mail address"},
      {"id": "name", "help": "Your full name"},
      {"id": "age", "help": "Your age (you must be over 16)"}
    ];

  for (var i = 0; i < helpText.length; i++) {
    var item = helpText[i];
    document.getElementById(item.id).onfocus = function() {
      showHelp(item.help);
    }
  }
}

setupHelp();

运行这段代码后,您会发现它没有达到想要的效果。无论焦点在哪个输入域上,显示的都是关于年龄的消息,
该问题的原因在于赋给 onfocus 是闭包(setupHelp)中的匿名函数而不是闭包对象;

解决这个问题的一种方案是使onfocus指向一个新的闭包对象。

function showHelp(help) {
  document.getElementById("help").innerHTML = help;
}

function makeHelpCallback(help) {
  return function() {
    showHelp(help);
  };
}

function setupHelp() {
  var helpText = [
      {"id": "email", "help": "Your e-mail address"},
      {"id": "name", "help": "Your full name"},
      {"id": "age", "help": "Your age (you must be over 16)"}
    ];

  for (var i = 0; i < helpText.length; i++) {
    var item = helpText[i];
    document.getElementById(item.id).onfocus = makeHelpCallback(item.help);
  }
}

setupHelp();
性能考量

如果不是因为某些特殊任务而需要闭包,在没有必要的情况下,在其它函数中创建函数是不明智的,因为闭包对脚本性能具有负面影响,包括处理速度和内存消耗。

例如,在创建新的对象或者类时,方法通常应该关联于对象的原型,而不是定义到对象的构造器中。原因是这将导致每次构造器被调用,方法都会被重新赋值一次(也就是说,为每一个对象的创建)。

考虑以下虽然不切实际但却说明问题的示例:

function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
  this.getName = function() {
    return this.name;
  };

  this.getMessage = function() {
    return this.message;
  };
}

上面的代码并未利用到闭包的益处,因此,应该修改为如下常规形式:

function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
}
MyObject.prototype = {
  getName: function() {
    return this.name;
  },
  getMessage: function() {
    return this.message;
  }
};

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85971.html

相关文章

  • JS 中的闭包什么

    摘要:大名鼎鼎的闭包面试必问。闭包的作用是什么。看到闭包在哪了吗闭包到底是什么五年前,我也被这个问题困扰,于是去搜了并总结下来。关于闭包的谣言闭包会造成内存泄露错。闭包里面的变量明明就是我们需要的变量,凭什么说是内存泄露这个谣言是如何来的因为。 本文为饥人谷讲师方方原创文章,首发于 前端学习指南。 大名鼎鼎的闭包!面试必问。请用自己的话简述 什么是「闭包」。 「闭包」的作用是什么。 首先...

    Enlightenment 评论0 收藏0
  • 什么闭包?为什么闭包?使用闭包应注意什么

    摘要:一什么是闭包闭包是指有权访问另一个函数作用域中的变量的函数。就是创建了一个匿名函数调用函数解除对匿名函数的引用,以便释放内存 一、什么是闭包? 闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式就是在一个函数内部创建另一个函数。 二、为什么要闭包 说明:变量分为全局变量的局部变量,全局变量的作用域为全局作用域,局部变量作用域为局部作用域。之前一篇文章关于作用域链给了介绍...

    raledong 评论0 收藏0
  • 面试官问我:什么JavaScript闭包,我该如何回答

    摘要:到底什么是闭包这个问题在面试是时候经常都会被问,很多小白一听就懵逼了,不知道如何回答好。上面这么说闭包是一种特殊的对象。闭包的注意事项通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。从而使用闭包模块化代码,减少全局变量的污染。 闭包,有人说它是一种设计理念,有人说所有的函数都是闭包。到底什么是闭包?这个问题在面试是时候经常都会被问,很多小白一听就懵逼了,不知道如何回答好。这个...

    BenCHou 评论0 收藏0
  • 多层级理解闭包

    摘要:第二梯队理解有了第一梯队的认识,我们慢慢修正大脑中对闭包的认识。理解这句话就可以很好的与闭包这两个字关联起来理解闭包这个概念了。总结第二梯队理解闭包是一个有特定功能的函数。第四梯队理解闭包通过访问外部变量,一个闭包可以维持这些变量。 闭包 闭包的概念困惑了我很久,记得当时我面试的时候最后一面有一个问题就是问题关于闭包的问题,然而到现在已经完全不记得当时的题目是啥了,但仍然能够回忆起当时...

    nemo 评论0 收藏0
  • The Little JavaScript Closures

    摘要:写在前面本文尝试模仿的风格,介绍的闭包。本文同时也是我学习闭包的一次总结。注根据这篇文章,事实上所有函数在创建的时候都会形成闭包。但这种闭包并没什么趣味,也没什么特别的用途,所以我们更关注的是由内部函数形成的闭包。 写在前面 本文尝试模仿 The Little Schema 的风格,介绍 JavaScript 的闭包。本文同时也是我学习 JavaScript 闭包的一次总结。欢迎一起讨...

    Heier 评论0 收藏0
  • 什么闭包闭包的优缺点?

    摘要:什么是闭包闭包的优缺点闭包是的一大难点,也是它的特色。闭包的用途闭包可以用在许多地方。闭包会在父函数外部,改变父函数内部变量的值。 什么是闭包?闭包的优缺点? 闭包(closure)是javascript的一大难点,也是它的特色。很多高级应用都要依靠闭包来实现。 1、变量作用域 要理解闭包,首先要理解javascript的特殊的变量作用域。变量的作用域无非就两种:全局变量和局部变量。...

    fireflow 评论0 收藏0

发表评论

0条评论

zxhaaa

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<