预编译

javascript预编译部分

  JavaScript当中不向其他的语言一样,在js中我们会看到一些奇怪的现象就像我们可以在函数声明之前去访问这个函数的名字,并且能够打印出函数体,而且我们还能在变量声明之前去访问这个变量,虽然值是一个undefined但是并没有报错,这些特殊的情况,归结于函数的预编译过程。

console.log(foo);
function foo(){}

  这样的一段代码,根据javascript解释执行的情况,本应该是报错的,因为找不到函数的啊。但是这里的并没有报错,这里打印出来的是整个函数体。同样这样的情况还有我们可以在变量声明之前访问该变量,这种情况被总结为,函数声明整体提升,变量声明声明提升,提升的场所是整个作用域逻辑的最顶端。

两个不一样的全局变量

  1. 暗示全局变量(imply global): 当一个变量未经声明就赋值的时候他就被当作是全局变量, 归window所有。

function foo() {
   var a = b = 123;
}
foo();
console.log(b); //123

  这里的b就成了暗示全局变量,使得我们在函数的外部能够访问到。

  2. 一切声明在全局当中的变量都是window对象的属性

var a = 123;
console.log(window.a); // 123

  它们的区别是,经过声明的全局变量是无法被delete操作符删除,但是未经声明的全局变量能够被delete删除掉。

  

js执行的三部曲

  1. 语法分析   这里是js引擎对全部的代码做一个简单的浏览,检查是否有低级错误。

  2. 预编译   发生在函数执行的前一刻,预编译之后会生成相应的GO(global object 全局对象) 和AO(activtion object 活动对象)

  3. 解释执行     函数执行期间变量的动态变化即GO/AO两个变量当中的属性值的动态更替。

预编译(函数内部)

  1. 生成一个AO对象(activtion object 执行期上下文)

  2. 找形参和变量声明,将变量和形参名作为AO对象的属性名,值为undfined

  3. 将实参和形参的值相统一,就是将函数的实参赋值给形参

  4. 在函数体内部找到函数声明(注意是函数声明,函数表达式情况是不一样的),值赋予函数体

由于是动态变化的,我用一个例子来说明预编译的过程:

  函数test:

  

  这里的例子看起来很麻烦,一个名字用在很多地方,很容易将人弄得昏头转向,所以一个合理的规则很重要!!!

  1. 生成一个AO对象

  AO = { }

  2. 找形参和变量声明,将变量名和形参名作为AO对象的属性名,值为undefined

  

  3. 将实参和形参相统一

  

  4. 在函数体内部找到函数声明,值赋予函数体

  

  当我们将这个AO变量分离出来之后,函数就能够说是解释执行了,从上到下,根据这里面的值来动态改变,当然函数声明和变量声明是被提升了。

  根据AO对象当中的值可以知道:

  第一个log : 这个时候a自然是指的AO当中的a 即 function a() { }

  第二个log : 这时的b还没有被赋值操作或者其他的操作,所以也是AO对象当中的b即undefined

  第三个log : 这时发生了b = function b() { } 的赋值操作,所以此时的b为function () { } (这里的函数名是忽略的,因为这是函数表达式)

全局的预编译

  全局的预编译和局部的预编译相似,只是少了一个将形参和实参值相统一这一步,并且这里的活动对象的名字也变了,叫做Global Object。

  函数执行的过程中寻找变量是有顺序的,在函数内部,假如一个变量无法在当前AO中找到就会函数上一层函数的AO当中直到找到GO当中,这也就形成作用域链,接下来的内容当中会详细说明这些过程。

  

  

原文地址:https://www.cnblogs.com/yangfengyi/p/8597930.html

时间: 2024-11-22 16:09:26

预编译的相关文章

一张图掌握移动Web前端所有技术(大前端、工程化、预编译、自动化)

你要的移动web前端都在这里! 大前端方向:移动Web前端.Native客户端.Node.js. 大前端框架:React.Vue.js.Koa 跨终端技术:HTML 5.CSS 3.JavaScript 跨平台框架:React Native.Cordova 前端工程化:Grunt.Gulp.Webpack 前端预编译:Babel.Sass.Less 自动化测试:Jasmine.Mocha.Karma 一图在手,应有尽有! 更多信息参考:https://item.jd.com/12170351.h

mybatis深入理解之 # 与 $ 区别以及 sql 预编译

mybatis 中使用 sqlMap 进行 sql 查询时,经常需要动态传递参数,例如我们需要根据用户的姓名来筛选用户时,sql 如下: select * from user where name = "ruhua"; 上述 sql 中,我们希望 name 后的参数 "ruhua" 是动态可变的,即不同的时刻根据不同的姓名来查询用户.在 sqlMap 的 xml 文件中使用如下的 sql 可以实现动态传递参数 name: select * from user whe

JDBC编程之预编译SQL与防注入式攻击以及PreparedStatement的使用教程

在JDBC编程中,常用Statement.PreparedStatement 和 CallableStatement三种方式来执行查询语句,其中 Statement 用于通用查询, PreparedStatement 用于执行参数化查询,而 CallableStatement则是用于存储过程. 1.Statement       该对象用于执行静态的 SQL 语句,并且返回执行结果. 此处的SQL语句必须是完整的,有明确的数据指示.查的是哪条记录?改的是哪条记录?都要指示清楚.     通过调用

JavaScript的预编译和执行

JavaScript引擎,不是逐条解释执行javascript代码,而是按照代码块一段段解释执行.所谓代码块就是使用<script>标签分隔的代码段. 整个代码块共有两个阶段,预编译阶段和执行阶段 一.编译阶段 对于常见编译型语言(例如:Java)来说,编译步骤分为:词法分析->语法分析->语义检查->代码优化和字节生成. 对于解释型语言(例如JavaScript)来说,通过词法分析和语法分析得到语法树后,就可以开始解释执行了. (1)词法分析是将字符流(char strea

SQL Server 预编译执行SQLs

问题描述: MVC5项目,利用执行sql的方式获取数据,但是在利用预编译执行的时候报错了,字段XXXwhich was not supplied. 其实就是这个参数传了个null导致的.在传参数之前做个判断,如果为null就赋值为空串即可. if (string.IsNullOrEmpty(name)) { name = string.Empty; } String sql = "select a.Id,a.UserName,a.TrueName,ISNULL(b.OTM, '0') as Fl

浅谈VC++中预编译的头文件放那里的问题分析

用C++写程序,肯定要用预编译头文件,就是那个stdafx.h.不过我一直以为只要在.cpp文件中包含stdafx.h 就使用了预编译头文件,其实不对.在VC++中,预编译头文件是指放到stdafx.h中的头文件才会有效果.如下: file: stdafx.h // stdafx.h : include file for standard system include files, // or project specific include files that are used freque

创建Pch预编译文件

在Xcode6之前,创建一个新工程xcode会在Supporting files文件夹下面自动创建一个“工程名-Prefix.pch”文件,也是一个头文件,pch头文件的内容能被项目中的其他所有源文件共享和访问.是一个预编译文件. 首先说一下pch的作用: 1.存放一些全局的宏(整个项目中都用得上的宏) 2.用来包含一些全部的头文件(整个项目中都用得上的头文件) 3.能自动打开或者关闭日志输出功能 虽然用了很久的Xcode6但是项目是xcode5之前创建好的,所以一开始并没有发现缺少了这个pch

问题处理:找不到Pch预编译文件?

提醒:Xcode6之后就不再自动创建Pch预编译文件 在Xcode6之前,创建一个新工程xcode会在Supporting files文件夹下面自动创建一个“工程名-Prefix.pch”文件,也是一个头文件,pch头文件的内容能被项目中的其他所有源文件共享和访问.是一个预编译文件. 首先说一下pch的作用: 1.存放一些全局的宏(整个项目中都用得上的宏) 2.用来包含一些全部的头文件(整个项目中都用得上的头文件) 3.能自动打开或者关闭日志输出功能 猜测原因: 虽然用了很久的Xcode6但是项

C++预编译头文件

以前只是学过C++中的预编译头文件,但一直没用过:既然今天又遇到了这个问题,所以还是决定写点总结 算是做个笔记吧! 在C++中之所以出现预编译的概念主要是因为在C++项目中导致整个程序的编译过程变得很缓慢的一个很重 要的原因就是C++头文件的存在,在每一个.cpp文件中都会包含许多.h的头文件,如果所包含的头文件过多或过大 就会导致.cpp文件过大而编译缓慢,但是事实上在许多.cpp中所包含的头文件都是重复出现的,即有很多头文件被 重复编译了许多次,这当然会导致项目整体的编译速度变慢. 为了解决

【java web】java执行预编译Groovy脚本

在JVM中运行Groovy类有两种方式: 使用Groovy编译所有的*.groovy为java的*.class文件,把这些*.class文件放在java类路径中,通过java类加载器来加载这些类. 通过groovy类加载器在运行时直接加载*.groovy文件并生成对象.在这种方式下,没有生成任何*.class,但是生成了一个java.lang.Class对象的实例. 下面介绍前一种使用Groovy的方法:编译成java字节码并且作为正常java应用程序运行在java虚拟机上,即预编译模式. 1.