首先,我们编程都是用的高级语言(写汇编和机器语言的大牛们除外),计算机不能直接理解高级语言,只能理解和运行机器语言,所以必须要把高级语言翻译成机器语言,计算机才能运行高级语言所编写的程序。
一.先说说编译型语言
1.定义:
程序在执行之前需要一个专门的编译过程,把程序编译成为
机器语言的文件,运行时不需要重新翻译,直接使用编译的
结果就行了。程序执行效率高,依赖编译器,跨平台性差些。
2.有哪些编译型语言:
C/C++、Pascal/Object Pascal(Delphi)、Golang
典型的就是它们可以编译后生成.exe文件,之后无需再次
编译,直接运行.exe文件即可。
3.例子:(C和C++)
以C语言为例:
#include<stdio.h>
int main(){
printf("helloword");
return 0;
}
安装mingw-get-setup.exe安装gcc和g++,C语言用gcc命令来编译
path配置gcc的环境变量.PNG
编译C程序生成exe并执行.PNG
生成exe文件.PNG
以C++语言为例:
#include <iostream>
using namespace std;
int main()
{
cout<<"hello atom"<<endl;
return 0;
}
上面已经安装了mingw-get-setup,用的是g++命令来编译
编译C++程序生成exe并执行.PNG
生成exe文件.PNG
2.然后再来说说解释型语言
1. 定义:程序不需要编译,程序在运行时才翻译成机器语言,每执行
一次都要翻译一次。因此效率比较低。在运行程序的时候才翻译,专门有
一个解释器去进行翻译,每个语句都是执行的时候才翻译。效率比较低,
依赖解释器,跨平台性好.
2.有哪些解释型语言:Java、C#、PHP、JavaScript、VBScript、
Perl、Python、Ruby、MATLAB 等等
3.例子:
(1)以Java为例(解释型+编译型语言)
java是通过javac.exe编译成.class文件 然后通过jvm加载.class文件,然后调用java.exe执行文件。在此之前你要下载安装JDK并配置环境变量。
public class Test{
public static void main(String args[]){
System.out.println("Hello");
}
}
编译java文件.png
执行java文件.png
(2)以C#为例(解释型语言)
讲到C#必须要说到CLR和.NET FrameWork。.Net是一种解决方案; C#
是.Net解决方案中的一种语言; CLR是.Net的运行架构.
《1》CLR是公共语言运行库(Common Language Runtime)和Java虚拟机
一样也是一个运行时环境,它负责资源管理(内存分配和垃圾收集等),并保
证应用和底层操作系统之间必要的分离。
《2》.NET FrameWork的核心是其运行库执行环境,称为公共语言运行库(Common Language Runtime)。
《3》作用:
(1)CLR是一个类似于JVM的虚拟机,为微软的.Net产品提供运行环境。
(2)CLR上实际运行的并不是我们通常所用的编程语言(例如C#、VB等),而是一种字节码形态的“中间语言”。
这意味着只要能将代码编译成这种特定的“中间语言”(MSIL),任何语言的产品都能运行在CLR上。
(3)CLR通常被运行在Windows系统上,但是也有一些非Windows的版本。这意味着.Net也很容易实现
“跨平台”。(至于为什么大家的印象中.Net的跨平台性不如Java,更多的是微软商业战略导致的)。
语言支持:
微软已经为多种语言开发了基于CLR的编译器,这些语言包括:C++/CLI、C#、Visual Basic、F#、
Iron Python、 Iron Ruby和IL。除此之外,其他的一些公司和大学等机构也位一些语言开发了基于CLR
的编译器,例如Ada、APL、Caml、COBOL、Eiffel、Forth、Fortran、Haskell、Lexicon、LISP、
LOGO、Lua、Mercury、ML、Mondrian、Oberon、Pascal、Perl、PHP、Prolog、RPG、Scheme、
Smaltak、Tcl/Tk。
CLR为不同的编程语言提供了统一的运行平台,在很大程度上对上层开发者屏蔽了语言之间才特性差异。
对于CLR来说,不同语言的编译器(Compiler)就相当于一个这种语言的代码审查者(Checker),所做的
工作就是检查源码语法是否正确,然后将源码编译成CLR所需要的中间语言(IL)。所以编程语言对于CLR
是透明的,也就是说CLR只知道IL的存在,而不知道IL是由哪种语言编译而来。
功能:
(1)基类库支持 (Base Class Library Support)
(2)内存管理 (Memory Management)
(3)线程管理 (Thread Management)
(4)垃圾回收 (Garbage Collection)
(5)安全性 (Security)
(6)类型检查 (Type Checker)
(7)异常处理 (Exception Manager)
(8)即时编译 (JIT)
using System;
namespace Animal
{
public class Cat
{
public static void Main(string[] args)
{
Console.WriteLine("cat");
}
}
}
csc.exe编译C#命令.png
调用csc命令编译.png
vb的解释器CLR
vbc.png(3)脚本语言也是解释型语言,比如vbscript,javascript,installshield script,ActionScript等等,脚本语言不需要编译,可以直接用,由解释器来负责解释。
例如javascript:
JavaScript引擎,不是逐条解释执行javaScript代码,而是按照代码块
一段段解释执行。所谓代码块就是使用<script>标签分隔的代码段。
编译阶段:
对于常见编译型语言(例如:Java)来说,编译步骤分为:词法分析->
语法分析->语义检查->代码优化和字节生成。
对于解释型语言(例如JavaScript)来说,通过词法分析和语法分析得到
语法树后,就可以开始解释执行了。
(1)词法分析是将字符流(char stream)转换为记号流(token stream),就
像英文句子一个个单词独立翻译,举例:
代码:var result = testNum1 - testNum2;
词法分析后 :
NAME "result"
EQUALS
NAME "testNum1"
MINUS
NAME "testNum2"
SEMICOLON
(2)语法分析得到语法树,举例:
条件语句 if(typeof a == "undefined" ){ a = 0; } else { a = a; } alert(a);
当JavaScript解释器在构造语法树的时候,如果发现无法构造,就会报语
法错误,并结束整个代码块的解析。
(3)“预编译”(并非完全的顺序执行)
“function函数”是一等公民!编译阶段,会把定义式的函数优先执行,
也会把所有var变量创建,默认值为undefined,以提高程序的执行效率!
总结:当JavaScript引擎解析脚本时,它会在预编译期对所有声明的变量
和函数进行处理!并且是先预声明变量,再预定义函数!
JavaScript执行过程:
二、JavaScript执行过程
在解释过程中,JavaScript引擎是严格按着作用域机制(scope)来执行
的。JavaScript语法采用的是词法作用域(lexcical scope),
也就是说JavaScript的变量和函数作用域是在定义时决定的,
而不是执行时决定的,由于词法作用域取决于源代码结构,所以
JavaScript解释器只需要通过静态分析就能确定每个变量、函数
的作用域,这种作用域也称为静态作用域(static scope)。
补充:但需要注意,with和eval的语义无法仅通过静态技术实现,
实际上,只能说JS的作用域机制非常接近lexical scope。
JavaScript中的变量作用域在函数体内有效,无块作用域;
function func(){
for(var i = 0; i < array.length; i++){
//do something here.
}
//此时i仍然有值,及i== array.length
print(i);//如果在java语言中,则无效
}
JavaScript引擎在执行每个函数实例时,都会创建一个
执行环境(execution context)。
执行环境 中包含一个调用对象(call object), 调用对
象是一个scriptObject结构
(“运行期上下文”),用来保存内部变量表varDecls、
内嵌函数表 funDecls、父级引用列表upvalue等
语法分析 结构(注意:varDecls
和funDecls等信息是在语法分析阶段就已经得到,并
保存在语法树中。
函数实例执行时,会将这些信息从语法树复制到
scriptObject上)。
scriptObject是与函数相关的一套静态系统,与函数实
例的生命周期
保持一致,函数执行完毕,该对象销毁。
JavaScript引擎通过作用域链(scope chain)把多个
嵌套的作用域串连在一起,并借助这个链条帮助JavaScript
解释器检索变量的值 。这个作用域链相当于一个索引表,
并通过编号来存 储它们的嵌套关系。当JavaScript解释器
检索变量的值,会按着这个索引编号进行
快速查找,直到找到全局对象(global object)为止,如
果没有找到值,则传递一个特殊的undefined值。
案例分析:
var scope = "global";
scopeTest();
function scopeTest(){
alert(scope);
var scope = "local";
alert(scope);
}
打印结果:undefined,local;
分析:省略词法分析等过程...执行遇到函数调用scopeTest(),
创建一个调用对象(运行期上下文,函数执行完毕,该对象销毁)
,构造它的作用域链时,搜索函数中用var声明的变量放入该链(
在语法分析阶段就已经得到放在语法树中,此时只是拷贝过来)
,因此scope在整个函数
scopeTest内都是可见的(从函数体的第一行到最后一行)。虽
然函数scopeTest的作用域链上有全局对象,自然能够访问
到全局的scope, 但寻找变量时会沿着自身作用域链向上
逐个找,因此首先找到自己的scope:undefined。
如果函数引用了外部变量的值,则JavaScript引擎会为该函数创建
一个闭包体(closure),闭包体是一个完全封闭和独立的作用域,
它不会在函数调用完毕后就被JavaScript引擎当做垃圾进行回收。
闭包体可以长期存在,因此开发人员常把闭包体当做内存中的蓄水
池,专门用来长期保存变量的值。只有当闭包体的外部引用被全部
设置为null值时,该闭包才会被回收。当然,也容易引发垃圾泛滥,
甚至出现内存外溢的现象。
网友评论