文章目錄

解析机制

JavaScript是一门解释型的语言 , 想要运行js代码需要两个阶段

  1. 编译阶段: 编译阶段就是我们常说的JavaScript预解析(预处理)阶段,在这个阶段JavaScript解释器将完成把JavaScript脚本代码转换到字节码
  2. 执行阶段: 在编译阶段JavaScript解释器借助执行环境把字节码生成机械码,并从上到下按顺序执行

预解析时做什么

var , function声明的变量提升

  首先,创建一个当前执行环境下的活动对象,然后将用 var 声明的变量设置为活动对象的属性(也就是将其添加到活动对象当中)并将其赋值为undefined,然后将 function 定义的函数 也添加到活动对象当中

1
2
3
4
5
6
7
if( false ){
var aa = 20;
var bb = 30;
} function (){};
function BB(){};

var定义的aa,bb以及function定义的AA(),BB()都会被变量提升到window对象下面 提升后等同于如下代码:

1
2
3
4
5
6
7
8
var aa;
var bb;
function (){};
function BB(){};
if( false ){
aa = 20;
bb = 30;
}

注: 不是用var 定义的变量具有全局性, 但是并不会被提升, 只有在第一次执行到时才会出现在全局作用域中

函数声明与函数表达式在预解析的区别

  首先,我们知道解析器会对function定义的函数(也就是函数声明)在代码开始执行之前对其实行函数声明提升(function declaration hoisting),所以在函数声明之前调用该函数是不会在执行期间报错,但是函数表达式不同,函数表达式用 var 声明,也就是说解析器会对其变量提升,并对其赋值为undefined,然后在执行期间,等到执行到该var 变量的时候再将其变量指向一个function函数,所以在函数表达式之前执行该函数是会报错的。

1
2
3
4
5
AA();
function (){}; BB();
var BB = function(){};

AA();不会报错,因为是以function的变量提升,BB()会报错,因为是以var的变量提升,提升后代码等同于如下:

1
2
3
4
5
6
function (){};
var BB; AA();
BB();
BB = function(){};

注意: 函数声明提升以后并不会执行内部的代码, 在其内的变量声明也不会起作用, 而是等到函数第一次被调用时才会执行 如:

1
2
3
4
5
6
7
var AA = function(){
console.log(' AA ');
} function BB(){
console.log(' BB ');
}

单独这一段代码并不会起作用, 只有执行:

1
2
AA(); // 输出 AA
BB(); //输出 BB

function 覆盖

 若定义了两个同名的函数,则在预解析期间后面一个会覆盖签名一个

大专栏  js作用域其二:预解析ass="gutter">
1
2
3
4
5
6
7
8
9
AA();   // 输出 I am AA_2;
function (){
console.log('I am AA_1');
}; AA(); // 输出 I am AA_2;
function AA(){
console.log('I am AA_2');
}

提升后其代码等同于如下:

1
2
3
4
5
6
7
8
9
10
function AA(){
console.log('I am AA_1');
} function AA(){
console.log('I am AA_2');
} AA();
AA();

可以看到这是正常的函数声明覆盖

预解析把变量或函数解析到其运行时的环境中

解析器将变量提升并不是将所有的变量都提升到window对象下面,其提升的原则是提升到变量运行的环境(变量生效的词法作用域)顶端

1
2
3
4
5
6
7
aa = "I am aa";
function AA(){
console.log(aa); // 输出 aa 是 undefined
var aa = "I am aa in a function";
console.log(aa); //输出 aa 是 I am aa in a function
}
AA();

这里 aa 被变量提升,但是aa 没有被变量提升到 window下面,而是被提升到其运行的环境 (function(){ })() 中去,也就是等同于

1
2
3
4
5
6
7
8
aa = "I am aa";
function AA(){
var aa;
console.log(aa); // 输出 aa 是 undefined
aa = "I am aa in a function";
console.log(aa); //输出 aa 是 I am aa in a function
}
AA();

JavaScript“预解析”分段进行

所谓分段进行是按照< script >标签来分块进行预解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script>
AA(); // 输出 AA2;
function AA(){
console.log('AA1');
} function AA(){
console.log('AA2');
}
</script> <script>
function AA(){
console.log('AA3');
}
</script>

上面例子说明function函数声明是分块的,然而至于var变量的提升经过反复验证是不分块的( 此处如有不同意见请指教 )

参考

javascript解析机制——预解析
本文是在此篇博客的基础上进行了修改与扩充

js作用域其二:预解析的更多相关文章

  1. JS作用域概念-预解析规则

    // 作用域: // 域:空间.范围.区域…… // 作用:读.写 script 全局变量.全局函数 自上而下 函数 由里到外 {} 浏览器: “JS解析器” 1)“找一些东西” :var funct ...

  2. 14 (H5*) JS第4天 函数、作用域、预解析

    目录 1:函数的其他定义 2:函数作为参数 3:函数作为返回值 4:作用域 5:作用域链 6:预解析 7:预解析分段 复习 <script> /* * 复习: * 函数:把一些重复的代码封 ...

  3. JavaScript (四) js的基本语法 - - 函数练习、arguments、函数定义、作用域、预解析

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.函数练习 1.求最值 // - 求2个数中的最大值 function getMax(num1, nu ...

  4. JS基础研语法---函数基础总结---定义、作用、参数、返回值、arguments伪数组、作用域、预解析

    函数: 把一些重复的代码封装在一个地方,在需要的时候直接调用这个地方的代码就可以了 函数作用: 代码重用 函数的参数: 形参:函数定义的时候,函数名字后面的小括号里的变量 实参:函数调用的时候,函数名 ...

  5. javascript作用域、预解析笔记

    1.作用域     一般情况下,一段代码中所用到的名字并不总是有效可用的,     而限定这个名字(变量)的可用性的代码范围就是这个名字的作用域,可用有效的减少变量名冲突     2.js的作用域(e ...

  6. javascript里面的闭包,作用域,预解析

    函数的作用域 1.全局变量=公用卫生间 2.局部变量=次卧卫生间      局部变量 全局无法使用      局部声明变量不加var的话就变成全局变量(不推荐使用) 3.闭包=次卧的可以用自己的卫生间 ...

  7. JS中的预解析

    js预解析对于很多学习web前端开发的新手们很困扰,总是很难搞懂到底是个什么东西,今天零度就为大家简单的分析一下,争取让大家都明白! 首先,看一下下面的代码: alert(a); var a = 1; ...

  8. JS基础语法---预解析

    预解析:就是在解析代码之前   1. 预解析做什么事? 把变量的声明提前了----提前到当前所在的作用域的最上面 函数的声明也会被提前---提前到当前所在的作用域的最上面   举例: function ...

  9. 函数(定义、参数、return、变量、作用域、预解析)

    一.函数定义 1.方式一       function 函数名(参数){  函数体  }——————函数声明的方法 function fn(a){ console.log(a); }: 2.方式二  ...

随机推荐

  1. 吴裕雄--天生自然 pythonTensorFlow自然语言处理:Attention模型--训练

    import tensorflow as tf # 1.参数设置. # 假设输入数据已经转换成了单词编号的格式. SRC_TRAIN_DATA = "F:\\TensorFlowGoogle ...

  2. Android之布局RelativeLayout

    线性布局的weight属性在等比例分配时比较方便,但是对复杂的界面,嵌套多层LinearLayout布局会导致渲染变慢,占用更多系统资源:而使用RelativeLayout的话,可能仅仅需要一层就可以 ...

  3. sd卡分区步骤

    1.将sd卡通过优盘插在电脑上 2.fdisk  /dev/sdb 3.   m   //帮助 d    //删除分区 4.  n   //添加新的分区. p  //默认主分区 回车 +400M   ...

  4. Form表单中method="post/get'的区别

    Form提供了两种数据传输的方式--get和post.虽然它们都是数据的提交方式,但是在实际传输时确有很大的不同,并且可能会对数据产生严重的影响.虽然为了方便的得到变量值,Web容器已经屏蔽了二者的一 ...

  5. android打飞机游戏、MVP句子迷App、悬浮窗、RxJava+Retrofit、加载动画、定制计划App等源码

    Android精选源码 微信打飞机 android进度设置加载效果源码 Android新手引导库EasyGuide MVP-好看又好用的句子迷客户端 XFloatView 一个简易的悬浮窗实现方案 a ...

  6. 吴裕雄--天生自然 JAVA开发学习:发送邮件

    import java.util.*; import javax.mail.*; import javax.mail.internet.*; import javax.activation.*; pu ...

  7. 华硕X450j清灰教程

    近期本人电脑咳嗽,电脑发烧,风扇呼呼的吹(电脑风扇好像出了问题),去了电脑上商城买了一支止咳糖浆(HEATSINK COMPOUNDS)硅脂, 废话不多说了 1 ,当然要把电脑关了,卸下三排螺丝,然后 ...

  8. 怎么保证RabbitMQ和kafuka集群的高可用性?

    rabbitMQ有三种模式:单机模式,普通集群模式,镜像集群模式 RabbitMQ的高可用性   RabbitMQ是比较有代表性的,因为是基于主从做高可用性的,我们就以他为例子讲解第一种MQ的高可用性 ...

  9. logstash nested内嵌字段 field protobuf解码 codec 的解决办法

    logstash nested内嵌字段 field protobuf解码 codec 的解决办法 主要需求 logstash-codec 下https://www.elastic.co/guide/e ...

  10. linux进程(二)

    信号管理进程使用kill命令发送信号与进程通信定义守护进程的角色结束用户会话的进程 kill,killall,pgrep,pkill 对于进程的正常关闭的理解正常关闭程序的方法systemctl st ...