js代码解析机制:

js代码解析之前会创建一个如下的词法环境对象(仓库):LexicalEnvironment{ }

在扫描js代码时会把:

1、用声明的方式创建的函数的名字;

2、用var定义的变量的名字存到这个词法环境中;

3、同名的时候:函数声明会覆盖变量,下面的函数声明会覆盖上面的同名函数;

4、函数的值为:对函数的一个引用; 变量的值为undefined;

5、如果用函数表达式的方式创建一个函数:

var fn = function(){ } 这样词法环境中存的是一个变量名fn,并赋值为undefined;

在调用函数的时候如果在函数上面调用就会出现和变量一样的情况报错undefined;

这也是以两种不同方式创建函数的区别;

?
1
2
3
4
5
LexicalEnvironment(这个词法环境===window)
{
fn: 对函数的一个引用;
b:undefined;
}

用声明的方式创建的函数:

?
1
function fn(){ };

用var定义的变量:

?
1
var b=5;

每次调用函数的时候就会创建一个新的词法环境对象(仓库):LexicalEnvironment{ };
在解析函数内部的变量和函数声明的时候跟全局词法环境相同,不过有两点需要注意,如下:

?
1
2
3
4
5
LexicalEnvironment(这个词法环境===fn)
{
a:对函数的一个引用;(解析的时候函数声明把变量覆盖了,尽管变量已经被赋值为1)
b:2;(解析的时候把变量存在了词法环境里,同时赋值为2)
}
?
1
2
3
4
5
6
7
function fn (a,b){
  alert(a)// function a(){ }
  alert(b)//2
  var b= 100;
  function a(){ }
}
fn(1,2);

调用函数并传递参数的时候,词法环境里会再存变量名的同时赋值,如果是函数内部有同名的函数声明则会把传入的参数覆盖;如果形参只有一个,那么另一个实参则被赋值为undefined;

闭包:

定义:(有多种定义)

1、(比较通俗的定义):函数嵌套函数,内部函数可以引用外部函数的参数和变量,这些参数和变量不会被垃圾回收机制所回收;

2、在计算机科学中,闭包是词法闭包的简称,是引用了自由变量的函数,这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外(意思就是不会被销毁)。

3、闭包是由函数和其相关的引用环境组合而成的实体。(潜台词就是这个函数将和引用环境同时存在,必须有引用)

综合来说,不管怎么定义都是在围绕着两个本质:函数在引用变量,这个变量将不会被销毁。

什么叫做被引用的自由变量离开了创造它的环境?如下:

?
1
2
3
4
5
6
7
8
9
function fn(){
  var a = 10;
  var b = 20;
  return function fn2(){
    alert(a);
  }
}
var result = fn();
result();//10;

以上代码就是fn2在被return出去以后,离开了fn函数这个环境,但是在外部调用依然能够访问到fn的变量;

这就是被引用的变量不会被销毁;同理在自执行函数这个闭包里,虽然自执行函数在自身执行过后内部变量本该被垃圾回收机制所回收,但是由于其内部有引用它的变量的子函数,也就是说构成了闭包,它的变量依然不会被销毁;

由此可见闭包的一个作用就是:我们能够通过闭包的方法来在外部访问到一个内部函数的变量;

很多人在解释闭包的时候都会把子函数return出去以后在外部调用,其实无论在哪里调用,闭包都已经形成了,只要是函数嵌套函数,并且子函数引用了父函数的变量,(不论子函数有没有被调用,这个用一种方法证明:在子函数内部打断点,在f12中观察闭包里的内容,已经出现了引用函数,这时候调用还没有被执行)这个时候闭包已经形成了。

jQuery插件闭包的本质:就是形成了作用域链。

注意:形成闭包的条件:1、函数要嵌套;2、子函数要引用父函数的变量(如果没有引用,则不会形成闭包,如果是引用父函数的父函数的变量也会形成闭包);

父函数每调用一次,就会形成一个新的闭包(函数每调用一次,就 会复制一份),也就是说形成一个新的词法作用域,重新引用父函数的变量;

以下代码说明:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
function fn() {
  var num = 1;
  return function() {
    num++;
    alert(num);
  }
}
var result1 = fn();
result1();//2;
result1();//3;
var result2 = fn();
result2();//2;
result2();//3;

在fn被调用两次时,都形成了新的闭包,有各自新的词法作用域,所以result2的输出结果不受result1的影响;

函数每调用一次,都会复制一份新的,可以说明for循环里i的问题;

?
1
2
3
4
5
6
7
for (var i = 0; i < 5; i++) {
  (function(index){
    oDiv.onclick = function() {
      alert(index)
    }
  })(i)
}

自执行函数每调用一次都会复制一份新的,传进的i值也在变化,由于在函数静态作用域里,在预解析阶段已经确定了变量的作用域,所以子函数引用的父函数变量index只能是每次复制的那个父函数变量,所以就实现了我们想要取不同的i值的目的;

图片延迟加载闭包的用途:

1、匿名自执行函数

不污染全局变量,(否则被声明为全局变量的话别的函数可能误用这些变量;造成全局对象过于庞大,影响访问速度(因为变量的取值是需要从原型链上遍历的)。提高效率;

2、结果缓存:

我们开发中会碰到很多情况,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间利用闭包,它不会释放外部的引用,从而函数内部的值可以得以保留。,这样我们在第二次调用的时候,就会从缓存中读取到该资源。

3、实现封装;

4、实现类和继承(构造函数);

JavaScript解析机制与闭包原理实例详解的更多相关文章

  1. javascript解析机制、闭包详解

    js解析机制: js代码解析之前会创建一个如下的词法环境对象(仓库):LexicalEnvironment{ } 在扫描js代码时会把: 1.用声明的方式创建的函数的名字: 2.用var定义的变量的名 ...

  2. python描述符(descriptor)、属性(property)、函数(类)装饰器(decorator )原理实例详解

     1.前言 Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过google和阅读源码,现将自己的理解和心得记录下来,也为正在为了该问题 ...

  3. php单点登录实现原理实例详解

    单点登录SSO(Single Sign On)说得简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户的一次登录能得到其他所有系统的信任. 单点登录在大型网站里使用 ...

  4. 转载 《AngularJS》5个实例详解Directive(指令)机制

    <AngularJS>5个实例详解Directive(指令)机制 大漠穷秋 本文整理并扩展了<AngularJS>这本书第六章里面的内容,此书近期即将由电子工业出版社出版,敬请 ...

  5. 我的书籍《深入解析Java编译器:源码剖析与实例详解》就要出版了

    一个十足的技术迷,2013年毕业,做过ERP.游戏.计算广告,在大公司呆过,但终究不满足仅对技术的应用,在2018年末离开了公司,全职写了一本书<深入解析Java编译器:源码剖析与实例详解> ...

  6. javascript常用经典算法实例详解

    javascript常用经典算法实例详解 这篇文章主要介绍了javascript常用算法,结合实例形式较为详细的分析总结了JavaScript中常见的各种排序算法以及堆.栈.链表等数据结构的相关实现与 ...

  7. JavaScript学习笔记-实例详解-类(一)

    实例详解-类(一): //每个javascript函数(除了bind())都自动拥有一个prototype对象// 在未添加属性或重写prototype对象之前,它只包含唯一一个不可枚举属性const ...

  8. 041——VUE中组件之pros数据的多种验证机制实例详解

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. javascript解析机制——预解析

    JavaScript解析机制是什么? JavaScript解析过程分为两个阶段,一个是编译阶段,另外一个就是执行阶段. * 编译阶段         编译阶段就是我们常说的JavaScript预解析( ...

随机推荐

  1. 【云盘资料】Sql注入从菜鸟到高手系列教程

    [云盘资料]Sql注入从菜鸟到高手系列教程 ps:Sql注入从菜鸟到高手系列教程 链接:阅读原文获取资料:http://bbs.ichunqiu.com/thread-6851-1-1.html 反馈 ...

  2. 弹性盒子模型属性之flex-shrink

    上一次,我们已经了解过flex-grow的具体用法后,这周,让我们一起来见一下flex-basis这个属性. flex-shrink 定义项目的缩小比例,默认值为1,注意前提是空间不足的情况下,项目缩 ...

  3. ubuntu18.04安装redis

    首先更新源 sudo apt-get update 安装命令: sudo  apt-get install redis-server 查看tcp 连接 netstat -ap | grep  6379 ...

  4. Kali学习笔记3:TCPDUMP详细使用方法

    Kali自带Wireshark,但一般的Linux系统是不带的,需要自行下载,并且过程略复杂 而纯字符界面的Linux系统无法使用Wireshark 但是,所有Linux系统都会安装TCPDUMP:一 ...

  5. [Swift-2019力扣杯春季初赛]1. 易混淆数

    给定一个数字 N,当它满足以下条件的时候返回 true: 把原数字旋转180°以后得到新的数字. 如 0, 1, 6, 8, 9 旋转 180° 以后,得到了新的数字 0, 1, 9, 8, 6 . ...

  6. LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via the context: Root WebApplicationContext: startup date [Sun Jan 13 17:59:19 CST 2019]; root of context hierarch

    在运行项目时出现了:LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via ...

  7. 【spring】task 任务调度(定时任务)

    1.定时任务的几种实现可以看这里:http://gong1208.iteye.com/blog/1773177 2.需要导入spring的jar包,可以参看之前的[spring]相关文章 3.这里使用 ...

  8. selenium之 玩转鼠标键盘操作(ActionChains)

    用selenium做自动化,有时候会遇到需要模拟鼠标操作才能进行的情况,比如单击.双击.点击鼠标右键.拖拽等等.而selenium给我们提供了一个类来处理这类事件——ActionChains sele ...

  9. 基于openssl搭建https服务器

    1. 搭建web环境 我这里使用源码编译安装方式安装httpd.详情可以参加我的一篇博客http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_linux_1 ...

  10. 【原创】浅说windows下的中断请求级IRQL

    一 中断分类 根据中断源不同,可以将中断分为 硬件中断:硬件上产生的中断,可以来自处理器的内部和外部.处理器的外部中断可以来自各种PIN信号接口和Local APIC的LINT0和LINT1引脚,以及 ...