js 运行代码的时候分为几个步骤:语法分析 ==》预编译  ==》解释执行

语法解析:通篇扫描代码,查看语法是否出错

解释执行读一行 - 解释一行 - 执行一行

预编译执行的操作:

// 假设之前并没有定义a
console.log(a);

打印结果:Uncaught ReferenceError: a is not defined

这个大家应该都知道:在变量未定义时就对变量进行访问就会报错(typeof 列外)

再看一个例子:

 // 假设之前并没有定义变量a
console.log(a); var a = 123; console.log(a);

看上面代码会打印什么?会不会报错?

打印结果:

undefined
123

为什么这个没有报错:因为在预编译的时候对变量进行了提升即变量提升。 定义的变量的声明(var a ;)被提到了代码块的最前面,变量的赋值操作(a = 123)没有变化。

所以被编译后就相当于

 // 假设之前没有定义变量a
var a; console.log(a); a = 123; console.log(a);

看下面这个例子:

 // 假设之前没有定义test
console.log(test); var test = 123; function test () { } console.log(test);

打印结果:

function test () {}
123

为什么第二行的输出的不是undefined 了?执行步骤是什么样子的?

因为函数声明在编译的时候也会进行提升,叫做函数提升

执行步骤:

1、变量提升:var test; 提升到最前面。此时test = undefined;

2、函数提升:function test () {}; 提升到最前面并覆盖var test; 的声明。所以第二行打印function test () {}; 此时test = function test () {}

3、进行赋值操作 test = 123; 此时test = 123;

 function test (test) {
console.log(test); // function test(){var a = 789}
var test = 123;
function test () {
var a = 789;
};
console.log(test) ; // 123
} test(456);

Why?

变量提升和函数提升是如何实现的?

预编译执行步骤

(a) 函数内

1、在代码定义之后执行之前生成活动对象AO(Activation Object ) 空对象{}

2、查找函数体内的形参和变量,定义为AO的属性,赋值为undefined;

3、将实参跟形参统一,即把实参赋值给AO[形参]

4、查找函数里的函数声明,将函数声明赋值给AO 即 AO[函数名] = 函数

(b) 全局

1、在代码定义之后执行之前生成全局环境对象GO(Global variable Object ) 空对象{}

2、查找变量,定义为GO的属性,赋值为undefined;

3、查找函数声明,将函数声明赋值给GO 即 GO[函数名] = 函数;

以上面的例子分析预编译过程:

function test (test) {
console.log(test); // function test(){var a = 789}
var test = 123;
function test () {
var a = 789;
};
console.log(test) ; // 123
} test(456); var a = 111; /** 全局 **/
// 第一步:创建GO
// GO{};
// 第二步:查找变量定义为GO的属性,赋值为undefined;
// GO{
// a: undefined
// };
// 第三步:将函数声明赋值给GO
// GO{
// a: undefined,
// test: function test(test) {...}
// } /** function test(test){...} 函数内 **/
// 第一步: 创建AO
// AO {}
// 第二步: 查找形参和变量,定义为AO的属性, 赋值为undefined;
// AO {
// test: undefined
// }
// 第三步: 形参和实参统一
// AO {
// test: 456
// }
// 第四步:将函数声明给AO
// AO {
// test: function test() { var a = 789 }
// }

之后就是一步一步的执行代码了

function test (test) {
console.log(test); // function test(){var a = 789}
var test = 123;
function test () {
var a = 789;
};
console.log(test) ; // 123
} test(456); var a = 111; // test(456); 进入到function test (test) {...} 内部
// console.log(test); // 打印 function test(){var a = 789}
// var test = 123; 由于 test 变量的声明已经提升,所以这句只执行 test = 123; 即AO[test] = 123
// AO {
// test: 123
// }
// function test() {var a = 789} 已经提升
// console.log(test) //打印 123
// 退出function test (test) {...} 销毁AO
// var a = 111; 由于 a 变量已经提升,这句只执行赋值 a = 111; 即 GO[a] = 111;
// GO{
// a: 111,
// test: function test(test) {...}
// } // 当页面销毁时销毁GO

js 预编译的更多相关文章

  1. js预编译

    先来做三个测试 eg1: var a; a = 1; function a() {}; console.log(a); eg2: var a; function a() {}; console.log ...

  2. Handlebars.js 预编译(转)

    Handlebars.js 官网上对预编译1是这样说的: 你需要安装 Node.js 你需要在全局环境中,通过 Npm 安装 handlebars 包 然后你就可以通过命令预编译你的 handleba ...

  3. 关于js预编译以及js文件执行顺序的几个问题。

    关于js的执行原理,除去html页面中直接添加的代码,js代码的放置可以分为两类. //情形a           <script type="text/javascript" ...

  4. JS预编译详解

    我们都知道javascript是解释型语言,执行的特点呢是编译一行,执行一行.按照这个思路有时候我们在运行代码时会有一些令人费解的现象出现.下面我们一起来执行下面三段代码. <script> ...

  5. js预编译的四部曲

    众所周知javascript是解释性语言,主要特点为解释一行执行一行. 而在js运行时会进行三件事:1语法分析  2.预编译  3.解释执行 语法分析会在代码执行前对代码进行通篇检查,以排除一些低级错 ...

  6. js预编译和函数执行

    javascript 执行过程 1.语法检测(有没有基本的语法错误,例如中文,关键字错误...)2.词法分析(预编译) (1)创建全局GO(global object)对象 (2)对var声明的变量进 ...

  7. js预编译环节 变量声明提升 函数声明整体提升

    预编译四部曲 1.创建AO对象 2.找形参和变量声明,将变量和形参名作为AO属性名,值为undefined 3.将实参和形参统一 4.在函数体里面找函数声明,值赋予函数体 function fn(a) ...

  8. JS预编译过程

    GO和AO 变量的预编译 实例1 console.log(a); var a=1; console.log(a); 实际编译过程: 将a存入预编译对象中,赋值为undefined: 真正的赋值语句当程 ...

  9. Rails : css或js文件无法成功预编译或调用jquery类插件时预编译问题

    调用bootstrap css框架时,将bootstrap文件夹放入 vendor/assets/下 bootstrap文件结构如下:    [shenma@localhost demo]$ ls v ...

随机推荐

  1. 力扣337——打家劫舍 III

    这一篇也是基于"打家劫舍"的扩展,需要针对特殊情况特殊考虑,当然其本质还是动态规划,优化时需要考虑数据结构. 原题 在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃 ...

  2. Qt Installer Framework翻译(7-3)

    控制脚本 对于每个安装程序,您可以指定一个控制脚本,用来与安装程序的部分UI或功能进行交互.控制脚本可以在向导中添加和删除页面,更改现有页面,进行附加检查以及通过模拟用户单击来与UI交互.例如,这允许 ...

  3. ASP.NET MVC4 使用UEditor富文本

    原帖:http://user.qzone.qq.com/369175376/infocenter?ptlang=2052     第一步:先到http://ueditor.baidu.com/webs ...

  4. Qt常用UI控件读取、写入方法

    本文用途:快速备忘,方便调用,写熟了自然就记下了. [1.标签label] 读取:ui->label->text() 写入:ui->label->setText("p ...

  5. 数据结构 二维数组-->稀疏数组-->二维数组

    稀疏数组基本概念: 稀疏数组应用场景: 当一个数组大部分的元素为"0",或者为同一个值的数组时,可以使用稀疏数组来保存该数组 处理方法: 1>记录数组一共有几行几列,有多少不 ...

  6. Day10-Python3基础-协程、异步IO、redis缓存、rabbitMQ队列

    内容目录: Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitMQ队列 Redis\Memcached缓存 Paramiko S ...

  7. docker挂载war包到tomcat容器中的注意点和坑

    刚开始用docker,难免会遇到很多坑,这里分享一下: 一 挂载最好挂载目录 我刚开始挂载war包,结果发现容器里把挂载的war包当成目录了 二 本地路径必须是绝对路径,否则不管用 三 容器中使用vi ...

  8. maven jar 包问题

    1. Failure to transfer... 这种错误基本是所需要的 jar 包不存在,或者下载不完整,可去本地仓库查看相关 jar 文件的完整性 解决方案: 删除对应 jar 包,重新下载(删 ...

  9. 页面置换算法之Clock算法

    1.前言 缓冲池是数据库最终的概念,数据库可以将一部分数据页放在内存中形成缓冲池,当需要一个数据页时,首先检查内存中的缓冲池是否有这个页面,如果有则直接命中返回,没有则从磁盘中读取这一页,然后缓存到内 ...

  10. HTML5与HTML4的区别-----新增的常用标签

    做前端工程师这么长时间了, 对HTML5的一些标签的用法还不是很熟悉.这篇随笔算是对学过的知识的梳理.常言道,温故而知新  ~哈哈.里面有不正确的地方还望各位大牛们指正,评论. 在做网页时习惯把网页分 ...