相信很多人只知道闭包这个词但是具体是怎么回事就不太清楚了,最近在群里有很多小伙伴讨论这个问题但还是蒙眬眬的赶脚。索性就写了这篇文章来帮助大家一起理解闭包。

变量作用域

闭包其实想明白了很简单,但是在理解闭包之前,我们先温习一下作用域的概念不多说 直接上代码来的直接

  • 全局变量
var a = 1;
function f1(){
a++;
console.log(a);
}
f1();//2
f1();//3
  • 局部变量
function f1(){
var a = 1;
a++;
console.log(a);
}
f1();//2
f1();//2

我们大家都知道在函数内部定义的变量(使用var)为局部变量,在函数内部可以访问函数外部的变量和函数,但是在函数外部就访问不了函数内部的变量和函数了

闭包就是能够让我们在函数外部能访问到函数内部的变量和函数下面我们看一个史上最简单的一个闭包,真的不能再简单,你相信我

function f1(){
var str ='我在函数里面,外面的坏人找不到我!!哈哈';
var aa = function(){
alert(str);
}
return aa;
}
var b = f1();
b();

在这个例子中f1中的函数aa 就是一个闭包,什么 aa 不是一个函数么?那闭包也是一个函数咯? 对,闭包说白了 就是一个函数,只不过这个函数比较特殊而已,特殊到什么地方,从例子不难发现 aa 是声明在函数f1 内部的,同时又把这个函数aa当成返回值给return 出来了。然后 我们执行 var b = f1() 就相当于 var b = aa 但是 aa 是在函数内部定义的 通常情况下外部是无法访问的,这个时候我们就把这个函数aa 当成函数的返回值给抛出去,这样在外层就能访问到 aa了 由于 aa 又是在函数f1内部声明的 所以 我们变相的可以访问到函数f1中的变量。这就是闭包最基本的作用

同时它还有很多好处:

  • 希望一个变量长期驻扎在内存中
  • 避免全局变量的污染
  • 私有成员的存在

闭包的特性:

1.函数嵌套函数

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

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

简单的相信大家都能看懂,但是遇见复杂的就蒙蔽的,特别是和对象在一块

就拿今天群里讨论的一个例子来说吧

var sister = '大桃花';
var obj = {
sister:'大妹哒',
sis:function(){
var sister = '小妹哒';
return function(){
console.log(sister);
console.log(this.sister);
};
}
};
function place(){
var sister = '大福晋';
var girl = obj.sis();
girl();
}
place();

在这个例子中 糊弄人的就是 sister 在不同的作用域中都有定义,大兄弟莫慌张!我们一起来揭开它这神秘的面纱,看看到底是大妹哒还是小妹哒,place 调用 place内部声明了一个 sister 然后紧接着 又定义一个 girl = obj.sis();obj的sis方法 的返回值是一个函数 也就是说 girl最后被赋值为一个函数,先不要管这个函数是在哪,反正就是一个函数,然后紧接着girl被调用,再被调用之前 你要明白下面的这些东西函数声明的时候会创建一个作用域链 这个链条上面都有神马东西

  • this
  • 函数内部的变量 --->此函数声明时所在的作用域中的变量 --->....--->window(浏览器中的最顶层)
  • 函数参数(arguments

这3项中其中后两项是在函数声明的时候就被确定下来了,也就是说 函数的作用域链条是在函数声明的时候就确定了,而非是函数调用的时候,然而this 在函数声明是时不确定,而是在函数被调用的时候所确定的,至于怎么确定那就要看函数被调用时所在的对象,函数被调用无非就2中形式:

  • 直接调用(比如 getName()
  • 通过对象.函数的形式调用(比如 obj.getName()

这两种方式调用 第一种的调用方式中 函数中的this 是永远指向 window的(这里抛开 callapply);而第二种调用方式 函数中(这里通常称作方法)的this 是指向点前面的obj

下面我们再看上面的例子

先说 console.log(sister)

由于girl是一个函数的引用 ,而这个函数是在 obj.sis 函数中声明的 只不过是一个匿名函数而已,由于这个匿名函数内部和匿名函数的参数中都没有 sister 这个变量, 所以顺着作用域链往上查找 找到 obj.sis函数的作用中声明了 sister这个变量 找到之后就不再去往上查找(js中的很多机制都是这中情况 比如 原型集成中对象属性的查找规则也类似这样)这个时候 控制台就会输出 obj.sis中定义的 sister变量的值。

再来看 console.log(this.sister)

girl这个函数被调用时的环境 是 place函数内部 而 place 是在整个window作用域下的 所以 这里的this 是指向 window 的 因而 控制台输出结果 会是 window下的 sister

再看下面的例子

var a = 'window';
var sys = {
a:'sys',
getA:function(){
alert(this.a);
},
getAA:function(){
return function(){
alert(this.a);
}
}
}
sys.getA();//sys
sys.getAA()();//window

这个例子中sys.getA() 不用说 大家都能理解,第二个 可以这么来看 先看sys.getAA() 这个结果其实是一个函数你可以把他当成一个函数的名字 a ,变换一下写法 就是 sys.getAA()() 等价于:

var a = sys.getAA();
a();

由于 这是函数的直接调用 所以 这里的this指向 window 最后结果 就是 'window'.

就先说这么多吧 思路可能有点混乱,如果你有什么好的建议或者意见,欢迎指正!

浅谈js闭包的更多相关文章

  1. 浅谈js闭包(closure)

    相信很多从事js开发的朋友都或多或少了解一些有关js闭包(closure)的知识. 本篇文章是从小编个人角度,简单地介绍一下有关js闭包(closure)的相关知识.目的是帮助一些对js开发经验不是很 ...

  2. 浅谈Js闭包现象

    一.1.我们探究这个问题的时候如果按照正常的思维顺序,需要知道闭包是什么它是什么意思,但是这样做会让我们很困惑,了解这个问题我们需要知道它的来源,就是我们为什么要使用闭包,先不管它是什么意思!     ...

  3. 浅谈JS中的闭包

    浅谈JS中的闭包 在介绍闭包之前,我先介绍点JS的基础知识,下面的基础知识会充分的帮助你理解闭包.那么接下来先看下变量的作用域. 变量的作用域 变量共有两种,一种为全局变量,一种为局部变量.那么全局变 ...

  4. 浅谈JS中 var let const 变量声明

    浅谈JS中 var let const 变量声明 用var来声明变量会出现的问题: 1. 允许重复的变量声明:导致数据被覆盖 2. 变量提升:怪异的数据访问.闭包问题 3. 全局变量挂载到全局对象:全 ...

  5. 浅谈JS之AJAX

    0x00:什么是Ajax? Ajax是Asynchronous Javascript And Xml 的缩写(异步javascript及xml),Ajax是使用javascript在浏览器后台操作HT ...

  6. 浅谈 js 正则字面量 与 new RegExp 执行效率

    原文:浅谈 js 正则字面量 与 new RegExp 执行效率 前几天谈了正则匹配 js 字符串的问题:<js 正则学习小记之匹配字符串> 和 <js 正则学习小记之匹配字符串优化 ...

  7. 浅谈 js 字符串之神奇的转义

    原文:浅谈 js 字符串之神奇的转义 字符串在js里是非常常用的,但是你真的了解它么?翻阅<MDN String>就可以了解它的常见用法了,开门见山的就让你了解了字符串是怎么回事. 'st ...

  8. 浅谈 js 正则之 test 方法

    原文:浅谈 js 正则之 test 方法 其实我很少用这个,所以之前一直没注意这个问题,自从落叶那厮写了个变态的测试我才去看了下这东西.先来看个东西吧. var re = /\d/; console. ...

  9. 浅谈 js 数字格式类型

    原文:浅谈 js 数字格式类型 很多人也许只知道 ,123.456,0xff 之类的数字格式.其实 js 格式还有很多数字格式类型,比如 1., .1 这样的,也有 .1e2 这样的. 可能有人说这是 ...

随机推荐

  1. 高级 JsRender 模板功能

    转自:http://msdn.microsoft.com/zh-cn/magazine/hh975379.aspx 尽管模板很强大,但有时模板引擎提供的现成标准功能无法满足您的需求. 您可能要转换数据 ...

  2. MySql用statement实现DDL,DML,DQL的操作Demo

    Demo1 Connection connection=null; Statement stmt=null; int result=-1; try { Class.forName("com. ...

  3. 如何使用JSONP

    1.使用$.getJSON() $.getJSON(" http://跨域的dns/document!searchJSONResult.action?name1="+value1+ ...

  4. JqueryUI插件网络连接

    operamasks_UI官网 http://ui.operamasks.org/website/homepage.html EasyUI官网 http://www.jeasyui.com/index ...

  5. smarty练习:数据的增删改

    根据数据库中的三张表格:timu,xuanxiang,kemu来进行数据的增删改查,并且使用smarty模版将前端与后台分离开来 三张表格: 主页面后台 main.php: <?php //引入 ...

  6. BufferedInputStream

    package file; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStrea ...

  7. Objective-C 静态变量 使用方法

    详解Objective-C中静态变量使用方法 Objective-C中静态变量使用方法是本文要介绍的内容,Objective-C 支持全局变量,主要有两种实现方式:第一种和C/C++中的一样,使用&q ...

  8. 磁珠(FB)的选用

    1. 磁珠(FB)的单位是欧姆,而不是亨特,这一点要特别注意.因为磁珠的单位是按照它在某一频率 产生的阻抗来标称的,阻抗的单位也是欧姆.磁珠的 DATASHEET上一般会提供频率和阻抗的特性曲线图,一 ...

  9. qtpanel

    https://github.com/MadFishTheOne/qtpanel https://github.com/xiangzhai/qtpanel

  10. 介绍几个移动web app开发框架

    jQuery Mobile jQuery Mobile框架能够帮助你快速开发出支持多种移动设备的Mobile应用用户界面.jQuery Mobile最新版本是1.4.0,默认主题采用扁平化设计风格.j ...