JS的解析机制,是JS的又一大重点知识点,在面试题中更经常出现,今天就来唠唠他们的原理。首先呢,我们在我们伟大的浏览器中,有个叫做JS解析器的东西,它专门用来读取JS,执行JS。一般情况是存在作用域就存在解析,那它是怎么运行的呢。首先呢,然后分成两大步骤。

1 第一步叫做JS预解析,这一步骤实际上是一种准备工作把,在执行之前,它会先浏览整个代码,然后寻找三种东西。 1var  2 函数声明    我来分别解释一下。首先它会提取带var声明的变量,然后放到作用域中,但是不会提取变量的值,会先给他赋值为undefined。然后呢会找到函数声明(关于函数声明上个博文有说),然后会把整个函数包括内容放到作用域。函数的参数也会被放进去。

所以我们可以知道在代码运行前,所有带var声明的变量都提前被赋值为undefined,找到所有有名字的函数所有的内容和参数,都提前被解析。

2 第二步就是执行了,JS解析器会逐行解读代码,在这过程中,只有表达式可以修改预解析的值(比如 = + - * / % -- ++ ! 参数....()),其他的会跳过。

下面来看个简单的栗子

    var a; 

    alert(a); //undefined 来自预解析

    a = 3;  //逐行解读代码到这句的时候,表达式修改了预解析中a的值。

    alert(a); //

这是个很简单的代码,我们按照解析机制来分析下:

第一步,找函数声明和var,然后找到了 var a=1; 这一句,就把 a提取出来然后赋值为undefined。即此时 a=undefined。

第二步,逐行解读代码, var a; 不是表达式,跳过,第一个alert(a);由第一步可知此时a=undefined, a = 3;  是表达式,并且更改了a的值,于是现在a=3,

所以最后弹出的是3。

下面再看个稍微复杂点的栗子。

var a=1;
function fn1(){
  alert(a);
  var a =2 ;
alert(a);
}
fn1();
alert(a);

我们按照解析机制来分析下:
1 预解析:找到带var的a和函数fn1(),放到全局作用域。

全局仓库:

a =undefined
function fn1(){
  alert(a);
  var a =2 ;
alert(a);
}

2 运行,逐行解读代码

var a=1;  // 将全局a的值改成1
function fn1(){ // 这里不是能够产生改变的表达式,所以运行的时候直接跳过。
  alert(a); // 先找局部变量a undefined
  var a =2 ; // 更改了局部作用域里a的值
  alert(a); // 2
}
fn1(); // 注意,当遇见函数的调用的时候,也会对函数进行预解析和运行两步操作。原理是相同的。只是作用域需要注意。
alert(a);// 在全局作用域里找a.显然等于1
函数的解析过程:

1  预解析:有点需要注意,当函数有参数的时候,参数也会被预解析,根据var a =2 ;找到 a 放到局部仓库  且a =undefined (注意这和全局作用域里的不是一个a,因为作用域不同,所以互相是不影响的),

所以此时是有两个作用域

全局仓库:

a =1;
function fn1(){
  alert(a);
  var a =2 ;
  alert(a);
}

函数里的局部仓库:

a =undefined ;

2  逐行解读函数里面的代码:当读取到这里 alert(a); 会优先在局部仓库里找a ,弹出未定义 ,当局部没有的时候 会去全局找

解读到var a =2 ; 优先在局部仓库里找a,把值改为2;所以解读到函数里面的第二个 alert(a); 就等于2了,

解读到最后一个alert(a),因为在全部环境里执行,所以会在全局仓库里找a;弹出1。

这个栗子,比较长,认真看几遍,一定会会收获良多的。

再看一个有参数存在的栗子:

有参数函数:

var a = 1;
function fn1(a){
  alert(a); // 1 来自局部作用域参数a,而且这个值是全局作用域里面的a作为参数传进来的值。
  a = 2 ; 修改了局部作用域里的a的值
  var a;
  alert(a); //
}
fn1(a);
alert(a); // 1 来自全局作用域

这里全局的预解析就不用多说了,找到了整个函数,和 a =undefined  然后执行a =1 ,到函数调用的时候,开始了函数的解析.

函数解析过程

1 预解析的时候,也会找到参数a,并且把它放到局部作用域,赋值为a = undefined.

2 逐行解读代码:会从参数开始解读 参数相当于局部变量 fn1(a); 这里把全局作用域里面的a的值,当作参数传入,注意只是把值传入,两个a是互不影响的,

不在同一个作用域。所以函数中先弹出1,后来局部作用域里的a值被改为2,就弹出了2 ,。最后一句弹出了a是1,可以发现函数里面优先更改的是局部作用域里面的a.(当在局部找不到a的时候,会去全局找 并且可以修改全局的值,所以大家可以实验把参数去掉,弹出的就是1 2 2 了)

下面再看一种比较特殊的情况,

1 就是在预解析过程中,遇到重名的情况,这个时候规律就是这样的,会优先留下有内容的,简单来说就是:当函数与变量重名,留下函数,当函数与函数重名,留下后面的函数。栗子就不举了,大家自己实验一下。

2 当有多个作用域的时候 解析器 会先预解析第一块的作用域中的东西 然后运行完成以后 再去预解析下一块的作用域的东西 再运行,后面的作用域可以找到前面作用域留下的东西,反过来就不行。

注意 if for等不是一个作用域。

   今天写的比较多,其实知识点原理都差不多,都是我平常学习的笔记总结,希望对大家有用。我是沐晴,下篇不见不散喔。

浅谈JS的变量提升的更多相关文章

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

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

  2. 浅谈JS严格模式

    浅谈JS严格模式 简介 何为严格模式?严格模式(strict mode)即在严格的条件下运行,在严格模式下,很多正常情况下不会报错的问题语句,将会报错并阻止运行. 但是,严格模式可以显著提高代码的健壮 ...

  3. 浅谈JS中的闭包

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

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

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

  5. 浅谈js拖拽

    本文来自网易云社区 作者:刘凌阳 前言 本文依据半年前本人的分享<浅谈js拖拽>撰写,算是一篇迟到的文章. 基本思路 虽然现在关于拖拽的组件库到处都是,HTML5也把拖放纳入了标准.但考虑 ...

  6. 浅谈JS中的!=、== 、!==、===的用法和区别 JS中Null与Undefined的区别 读取XML文件 获取路径的方式 C#中Cookie,Session,Application的用法与区别? c#反射 抽象工厂

    浅谈JS中的!=.== .!==.===的用法和区别   var num = 1;     var str = '1';     var test = 1;     test == num  //tr ...

  7. 深入理解js的变量提升和函数提升

    一.变量提升 在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作用域和函数作用域.变量提升即将变量声明提升到它所在作用域的最开始的部分.上个简历的例子如: ...

  8. 浅谈JS之AJAX

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

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

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

随机推荐

  1. zabbix参考文档

    http://www.zsythink.net/archives/category/%E8%BF%90%E7%BB%B4%E7%9B%B8%E5%85%B3/zabbix/

  2. git 误删分支恢复方法

    在使用Git的过程中,因为人为因素造成分支(commit)被删除,可以使用以下步骤进行恢复. 首先用以下步骤创建一个新分支,修改一些文件后删除,以便进行恢复. 1.创建分支 abc git branc ...

  3. 【!Important】如何保证线程执行的先后顺序

    1.假设有三个线程,分别为T1.T2.T3,如果让线程T2在线程T1之后执行,在线程T3之前执行. 使用线程的join方法,该方法的作用是“等待线程执行结束”,即join()方法后面的代码块都要等待现 ...

  4. TIScript Graphics

    $(#main_frame).paintContent = function(gfx) { gfx.pushLayer(#background-area); gfx.translate(0.5,0.5 ...

  5. MyISAM和InnoDB区别 及选择

    MySQL默认采用的是MyISAM. MyISAM不支持事务,而InnoDB支持.InnoDB的AUTOCOMMIT默认是打开的,即每条SQL语句会默认被封装成一个事务,自动提交,这样会影响速度,所以 ...

  6. d4

    # s = '132a4b5c'# s1 = s[0]+s[2]+s[1]# print(s1)#使用while和for循环分别打印字符串s=’asdfer’中每个元素.s = 'fkld'# for ...

  7. CH 1601 - 前缀统计 - [字典树模板题]

    题目链接:传送门 描述给定 $N$ 个字符串 $S_1,S_2,\cdots,S_N$,接下来进行 $M$ 次询问,每次询问给定一个字符串 $T$,求 $S_1 \sim S_N$ 中有多少个字符串是 ...

  8. java获取文件的路径问题

    java获取文件的路径问题 在java中读取读取文件,经常因为路径的问题找不到,此文用于记录如何定位文件的简单方法. 本基于springboot做的测试,主要是构建工程方便,所用的方法都是JDK中的方 ...

  9. shell技巧之以逆序形式打印行

    测试文本内容如下: # cat textfile hadoop hdfs yarn spark zookeeper mapreduce hive hbase scala kafka CHAVIN my ...

  10. nginx url问题

    测试需求,url自动加/后,发现重定向不带端口,即为 test.a.com:3443/abc  nginx自动重定向301到 test.a.com/abc,端口消失. 分析可能和nginx默认配置se ...