很多js的框架与插件编写都用到了闭包,所以,阅读和掌握闭包很有必要。最近学习vue框架时,经常会猜想很多功能的native js实现,很多都应用到了闭包,闭包除了目前已知的一些特性,如:可以保持局部变量以减少对全局作用域的污染外,一些情况下必须用闭包才能实现。

先贴一个根据自己的理解绘制的闭包原理:

关于闭包的几个重要的知识点需要理解:

1. javascript中,每次运行函数,都会创建一个新的对象,用来保存函数的内部变量,称之为——局部变量保存对象

2. 每次运行外部函数,内部闭包函数都会被重新定义一遍

3. 函数运行时,局部变量保存对象会保存在函数定义时的作用域链中,当函数执行完毕后,没有其他引用指向该作用域链时,会释放上述对象;若有其他引用指向时(如函数运行结束后返回一个闭包的引用),该对象不会被释放。

一些遇到的,必须用闭包的情况:

一、for循环后的外部引用指向同一个作用域,和设计期待背道而驰

在模拟vue的数据监控逻辑时,刚开始写的代码如下:

    function Observe (obj){
for( prop in obj ){
var oldval = obj[prop];
Object.defineProperty( obj,prop,{
get:function(){
return oldval;
},
set:function(newval){
console.log( prop+'的数据改变了,老的值:'+oldval+"新的值:"+newval );
oldval = newval;
}
} );
}
} var data = {
name:'tester',
age:16,
class:'04071135'
}; Observe( data );

在firefox控制台打印data.name,状况如下:

很明显,虽然这里为data的每个属性(name,age,class)定义了getter和setter存取器——即每个属性的getter/setter外部应用都指向了每次重新定义的闭包,但这些闭包共享了一个父函数作用域,在循环执行完毕后,该作用域内挂在的变量对象信息如下:

prop: 'class';

oldval:'04071135'

所以,当调用虽有的外部引用——属性的存取器getter和setter时,访问的是同一个变量对象,所以,执行结果都是一样的,再多打印一些信息看看:

经上述分析可知,因为这些外部引用都指向了同一个作用域里的变量对象才导致的bug,解决的办法就是,让每个外部引用都能保有自己独立的作用域,这就想到了闭包:

修改上述Observe函数为:

    function Observe( obj ){
function defineprop( obj,prop ){
//在没有开始define之前获取属性值,这样就不会陷入死循环
var oldval = obj[prop];
Object.defineProperty(obj,prop,{
get:function(){
return oldval;
},
set:function(newval){
console.log( prop+'的数据改变了,老的值:'+oldval+"新的值:"+newval );
oldval = newval;
}
});
}
var keys = Object.keys( obj );
for( var i=0;i<keys.length;i++ ){
defineprop( obj,keys[i] );
}
} Observe( data );

再在控制台打印测试,结果如下:

这里就是运用了闭包的特点,虽然内部定义了defineprop函数后就调用了,如果没有外部引用指向时,就会释放defineprop里的prop,oldval等,但因为data的属性存取器指向了defineprop内的闭包(get和set),所以,defineprop里的局部变量得得以保留。每个属性存取器都有了自己的作用域—持久化的变量保存对象,因此,访问起来就没什么问题了。

再看下面一个小例子,是上面的简化版;

var obj_arr = [{},{},{}];

    for( var i=0;i<obj_arr.length;i++ ){
obj_arr[i]["getdata"] = function(){
return i;
}
}

此时在控制台访问一下对象的getdata看看:

这些引用均访问同一块公用的作用域;

根据上述的闭包思路重新改写代码:

    var obj_arr = [{},{},{}];
function addData( val ){
obj_arr[val]["getdata"] = function(){
return val;
}
}
for( var i=0;i<obj_arr.length;i++ ){
addData(i);
}

打印结果如下,正常。

二、闭包在作用域绑定方面也很有用

将方法的执行绑定在对象上以后,用户不用再关注方法执行的作用域,直接调用即可,这种思路的实现可以参考:https://www.cnblogs.com/surfer/p/9625725.html

未完待续...

javascript中闭包与作用域的理解的更多相关文章

  1. Javascript中闭包的作用域链

    作用域定义了在当前上下文中能够被访问到的成员,在Javascript中分为全局作用域和函数作用域,通过函数嵌套可以实现嵌套作用域. 闭包一般发生在嵌套作用域中.闭包是JavaScript最强大的特性之 ...

  2. 在Javascript中闭包(Closure)

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

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

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

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

    在JavaScript中闭包的作用和简单的用法 一.闭包的简介 作用域链:在js中只有函数有作用域的概念,由于函数内能访问函数外部的数据,而函数外部不能访问函数内部的数据,由上述形成一种作用域访问的链 ...

  5. javascript中的this作用域详解

    javascript中的this作用域详解 Javascript中this的指向一直是困扰我很久的问题,在使用中出错的机率也非常大.在面向对象语言中,它代表了当前对象的一个引用,而在js中却经常让我觉 ...

  6. JavaScript中call、apply个人理解

    JavaScript中call.apply个人理解 一句话即通俗的说:call.apply 是为了改变this的状态而存在的 }; } function personInfo(name,age){ t ...

  7. 对js中闭包,作用域,原型的理解

    前几天,和朋友聊天,聊到一些js的基础的时候,有一种‘好像知道,好像又不不知道怎么讲的感觉’...于是捡起书,自己理一理,欢迎拍砖. 闭包 理解闭包首先要理解,js垃圾回收机制,也就是当一个函数被执行 ...

  8. 对JavaScript中闭包的理解

    在前端开发中闭包是一个很重要的知识点,是面试中一定会被问到的内容.之前我对闭包的理解主要是"通过闭包可以在函数外部能访问到函数内部的变量",对闭包运用的也很少,甚至自己写过闭包自己 ...

  9. Javascript中闭包的个人理解

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

随机推荐

  1. Spring AOP监控SQL运行

    对数据库连接池Proxool比較熟悉的读者,都知道Proxool能够记录SQL运行内容和时间等信息日志. 我们能够将该日志记录专门的SQL日志文件.对于查找运行特别耗时的SQL起了不小的作用. 对于一 ...

  2. Redis入门教程(二)— 基本数据类型

    阅读以下内容时,手边打开一个redis-cli一起输入,输入命令敲击回车键前在心中想好你的答案,如果结果不合你的预期,请分析原因,使极大地提高学习效率.如果没有条件,每个数据类型后有代码运行结果,供你 ...

  3. dotnet new 命令

    如果想知道这个命令的详细用法,可以在打完命令之后,在输入一个" --help"即可 $ dotnet new --help.NET Initializer Usage: dotne ...

  4. IDEA-Maven的环境配置及使用

    一.Maven的下载 IDEA的往期下载地址:https://www.jetbrains.com/ 1.点击进入 1.往期的下载地址:http://www.apache.org/ 操作步骤:我们点击进 ...

  5. myecplise、ecplise项目空间优化

    1.代码自动提示补全 Window->preferences->Java->Editor->Content Assist 再右下角Auto activation trigger ...

  6. id 查询

    Ids Query | Elasticsearch Reference [6.2] | Elastic http://www.elastic.co/guide/en/elasticsearch/ref ...

  7. C# WinForm开发系列 - Form/Window

    Form是WinForm开发中非常重要的一个控件, 本文将包含如何制作一个关于对话框,系统载入提示窗体, 创建类似于QQ提示框以及创建不规则窗体等(文章及相关代码搜集自网络,仅供学习参考,版权属于原作 ...

  8. 使用C#开发HTTP服务器系列之访问主页

    各位朋友大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是http://qinyuanpei.com.在这个系列文章的第一篇中,我们着重认识和了解了HTTP协议,并在此基础上实现了一个可交互的W ...

  9. jQuery得到多个值只能用取Class ,不能用取ID

    如果页面有多个checkbox: <input type="checkbox"   class="checkApply"    id="chec ...

  10. thinkphp不能够将ueditor中的html文本显示

    因为这个问题花费了我好长时间,非常的急躁.fuck!! 这次我首先在富文本框中输入了一些文本,这些文本是带有样式的,比如是代码.然后存入数据库,但是当我再一次将它取出来打算放入富文本框中的时候,马丹, ...