轻松理解JavaScript闭包

 更新时间:2017年03月14日 11:41:54   作者:嵘么么  
闭包机制是JavaScript的重点和难点,本文希望能帮助大家轻松的学习闭包。下面跟着小编一起来看下吧

摘要

闭包机制是JavaScript的重点和难点,本文希望能帮助大家轻松的学习闭包

一、什么是闭包?

闭包就是可以访问另一个函数作用域中变量的函数。

下面列举出常见的闭包实现方式,以例子讲解闭包概念

function f1(){
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999
  nAdd();
  result(); // 1000

f1是f2的父函数,而f2被赋给了一个全局变量(return的值),这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收,这便形成了闭包。

因此,可以这么理解。闭包机制就是,如果A函数引用了另一个函数B的变量,但是B返回后A仍没有返回,仍存在,因为A的引用,所以B的所有局部变量并不会随B退出而注销,会一直存在,直到A注销。此时A就是闭包。

二、闭包的this指针

闭包通常在全局环境调用的,所以this通常指向window,具体情况还是需要视执行环境而言,总之this指向执行环境。

若需要闭包的this指向闭包的包含对象,则需要将包含对象的this作为变量传进闭包。

三、使用闭包的注意点

  1. 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
  2. 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

四、解决一道闭包常见面试题

问题:

function onMyLoad(){
  /*
  抛出问题:
  此题的目的是想每次点击对应目标时弹出对应的数字下标 0~4,但实际是无论点击哪个目标都会弹出数字5
  问题所在:
  arr 中的每一项的 onclick 均为一个函数实例(Function 对象),这个函数实例也产生了一个闭包域,
  这个闭包域引用了外部闭包域的变量,其 function scope 的 closure 对象有个名为 i 的引用,
  外部闭包域的私有变量内容发生变化,内部闭包域得到的值自然会发生改变
  */
  var arr = document.getElementsByTagName("p");
  for(var i = 0; i < arr.length;i++){
  arr[i].onclick = function(){
   alert(i);
  }
  }
 }

解决方法

1、在外面再加一层函数,将i作为函数参数传进来,这样每次保存的是函数内部的变量,与外部i不是同一个内存空间,而每次调用函数都会生成一个局部变量,所以可以保证每次保存的值互不影响。

for(var i = 0; i<arr.length;i++){
 arr[i].onclick = (function(arg){
  return function () {
   alert(arg);
  }
 })(i);
}

2、用ES6新特let,将for循环的var i改成let i,这样当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量。你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持脚本之家!

相关文章

  • 浅析ES6与CommonJS中模块的用法对比

    浅析ES6与CommonJS中模块的用法对比

    ES6 的模块化汲取了 CommonJS 和AMD 的优点,拥有简洁的语法和异步的支持,并且写法也和 CommonJS 非常的相似,下面我们就来看看二者用法的差异吧
    2023-09-09
  • JS利用时间戳倒计时的实现示例

    JS利用时间戳倒计时的实现示例

    这篇文章主要介绍了JS利用时间戳倒计时的实现示例,本文将提供代码示例和详细的步骤,帮助你实现一个简单而实用的时间戳倒计时,感兴趣的可以了解一下
    2023-12-12
  • 利用JavaScript实现简单的网页时钟

    利用JavaScript实现简单的网页时钟

    这篇文章主要介绍了利用JavaScript实现简单的网页时钟,主要使用了js的日期对象,实现的时候先创建一个日期对象,并进行网页布局,对时间获取之后将时间填入对应的标签内。然后使用多线程实现时钟的变动,需要的朋友可以参考一下
    2022-02-02
  • 关于laydate.js加载laydate.css路径错误问题解决

    关于laydate.js加载laydate.css路径错误问题解决

    日期时间选择插件 laydate.js相信对大家来说都不陌生,这篇文章主要给大家介绍了关于laydate.js加载laydate.css路径错误问题解决的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-12-12
  • 原生JS实现点击数字小游戏

    原生JS实现点击数字小游戏

    这篇文章主要为大家详细介绍了原生JS实现点击数字小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • js自定义事件代码说明

    js自定义事件代码说明

    在研发公展公用后台的时候,用了许多的技巧性的JS,最有代表性就是如下这一例子.
    2011-01-01
  • JSON 对象未定义错误的解决方法

    JSON 对象未定义错误的解决方法

    下面小编就为大家带来一篇JSON 对象未定义错误的解决方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09
  • 移动端网页开发调试神器Eruda的介绍与使用技巧

    移动端网页开发调试神器Eruda的介绍与使用技巧

    在日常的移动端开发时,一般都是试用chrome浏览器的移动端模式进行开发和调试,只有在chrome调试完成,而最近发现了一个新的调试方法,所以这篇文章主要给大家介绍了关于移动端网页开发调试神器Eruda的基本资料,以及其使用的一些技巧,需要的朋友可以参考下。
    2017-10-10
  • openlayers4实现点动态扩散

    openlayers4实现点动态扩散

    这篇文章主要为大家详细介绍了openlayers4实现的点动态扩散,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-08-08
  • 对 lightbox JS 图片控件进行了一下改造, 使其他支持复杂的图片说明

    对 lightbox JS 图片控件进行了一下改造, 使其他支持复杂的图片说明

    如果要为图片添加详细的图片说明,并为图片的说明设置一些格式,如字体的大小、颜色等,那么使用 title 这个属性来设置这些说明信息是没办法实现的。
    2010-03-03

最新评论