首先,我們編程都是用的高級語言(寫匯編和機器語言的大牛們除外),計算機不能直接理解高級語言,只能理解和運行機器語言,所以必須要把高級語言翻譯成機器語言,計算機才能運行高級語言所編寫的程序。
一.先說說編譯型語言
1.定義:
程序在執(zhí)行之前需要一個專門的編譯過程,把程序編譯成為
機器語言的文件,運行時不需要重新翻譯,直接使用編譯的
結(jié)果就行了。程序執(zhí)行效率高,依賴編譯器,跨平臺性差些。
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的環(huán)境變量.PNG
編譯C程序生成exe并執(zhí)行.PNG
生成exe文件.PNG
以C++語言為例:
#include <iostream>
using namespace std;
int main()
{
cout<<"hello atom"<<endl;
return 0;
}
上面已經(jīng)安裝了mingw-get-setup,用的是g++命令來編譯
編譯C++程序生成exe并執(zhí)行.PNG
生成exe文件.PNG
2.然后再來說說解釋型語言
1. 定義:程序不需要編譯,程序在運行時才翻譯成機器語言,每執(zhí)行
一次都要翻譯一次。因此效率比較低。在運行程序的時候才翻譯,專門有
一個解釋器去進行翻譯,每個語句都是執(zhí)行的時候才翻譯。效率比較低,
依賴解釋器,跨平臺性好.
2.有哪些解釋型語言:Java、C#、PHP、JavaScript、VBScript、
Perl、Python、Ruby、MATLAB 等等
3.例子:
(1)以Java為例(解釋型+編譯型語言)
java是通過javac.exe編譯成.class文件 然后通過jvm加載.class文件,然后調(diào)用java.exe執(zhí)行文件。在此之前你要下載安裝JDK并配置環(huán)境變量。
public class Test{
public static void main(String args[]){
System.out.println("Hello");
}
}

編譯java文件.png

執(zhí)行java文件.png
(2)以C#為例(解釋型語言)
講到C#必須要說到CLR和.NET FrameWork。.Net是一種解決方案; C#
是.Net解決方案中的一種語言; CLR是.Net的運行架構(gòu).
《1》CLR是公共語言運行庫(Common Language Runtime)和Java虛擬機
一樣也是一個運行時環(huán)境,它負責資源管理(內(nèi)存分配和垃圾收集等),并保
證應用和底層操作系統(tǒng)之間必要的分離。
《2》.NET FrameWork的核心是其運行庫執(zhí)行環(huán)境,稱為公共語言運行庫(Common Language Runtime)。
《3》作用:
(1)CLR是一個類似于JVM的虛擬機,為微軟的.Net產(chǎn)品提供運行環(huán)境。
(2)CLR上實際運行的并不是我們通常所用的編程語言(例如C#、VB等),而是一種字節(jié)碼形態(tài)的“中間語言”。
這意味著只要能將代碼編譯成這種特定的“中間語言”(MSIL),任何語言的產(chǎn)品都能運行在CLR上。
(3)CLR通常被運行在Windows系統(tǒng)上,但是也有一些非Windows的版本。這意味著.Net也很容易實現(xiàn)
“跨平臺”。(至于為什么大家的印象中.Net的跨平臺性不如Java,更多的是微軟商業(yè)戰(zhàn)略導致的)。
語言支持:
微軟已經(jīng)為多種語言開發(fā)了基于CLR的編譯器,這些語言包括:C++/CLI、C#、Visual Basic、F#、
Iron Python、 Iron Ruby和IL。除此之外,其他的一些公司和大學等機構(gòu)也位一些語言開發(fā)了基于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為不同的編程語言提供了統(tǒng)一的運行平臺,在很大程度上對上層開發(fā)者屏蔽了語言之間才特性差異。
對于CLR來說,不同語言的編譯器(Compiler)就相當于一個這種語言的代碼審查者(Checker),所做的
工作就是檢查源碼語法是否正確,然后將源碼編譯成CLR所需要的中間語言(IL)。所以編程語言對于CLR
是透明的,也就是說CLR只知道IL的存在,而不知道IL是由哪種語言編譯而來。
功能:
(1)基類庫支持 (Base Class Library Support)
(2)內(nèi)存管理 (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

調(diào)用csc命令編譯.png
vb的解釋器CLR

vbc.png
(3)腳本語言也是解釋型語言,比如vbscript,javascript,installshield script,ActionScript等等,腳本語言不需要編譯,可以直接用,由解釋器來負責解釋。
例如javascript:
JavaScript引擎,不是逐條解釋執(zhí)行javaScript代碼,而是按照代碼塊
一段段解釋執(zhí)行。所謂代碼塊就是使用<script>標簽分隔的代碼段。
編譯階段:
對于常見編譯型語言(例如:Java)來說,編譯步驟分為:詞法分析->
語法分析->語義檢查->代碼優(yōu)化和字節(jié)生成。
對于解釋型語言(例如JavaScript)來說,通過詞法分析和語法分析得到
語法樹后,就可以開始解釋執(zhí)行了。
(1)詞法分析是將字符流(char stream)轉(zhuǎn)換為記號流(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解釋器在構(gòu)造語法樹的時候,如果發(fā)現(xiàn)無法構(gòu)造,就會報語
法錯誤,并結(jié)束整個代碼塊的解析。
(3)“預編譯”(并非完全的順序執(zhí)行)
“function函數(shù)”是一等公民!編譯階段,會把定義式的函數(shù)優(yōu)先執(zhí)行,
也會把所有var變量創(chuàng)建,默認值為undefined,以提高程序的執(zhí)行效率!
總結(jié):當JavaScript引擎解析腳本時,它會在預編譯期對所有聲明的變量
和函數(shù)進行處理!并且是先預聲明變量,再預定義函數(shù)!
JavaScript執(zhí)行過程:
二、JavaScript執(zhí)行過程
在解釋過程中,JavaScript引擎是嚴格按著作用域機制(scope)來執(zhí)行
的。JavaScript語法采用的是詞法作用域(lexcical scope),
也就是說JavaScript的變量和函數(shù)作用域是在定義時決定的,
而不是執(zhí)行時決定的,由于詞法作用域取決于源代碼結(jié)構(gòu),所以
JavaScript解釋器只需要通過靜態(tài)分析就能確定每個變量、函數(shù)
的作用域,這種作用域也稱為靜態(tài)作用域(static scope)。
補充:但需要注意,with和eval的語義無法僅通過靜態(tài)技術(shù)實現(xiàn),
實際上,只能說JS的作用域機制非常接近lexical scope。
JavaScript中的變量作用域在函數(shù)體內(nèi)有效,無塊作用域;
function func(){
for(var i = 0; i < array.length; i++){
//do something here.
}
//此時i仍然有值,及i== array.length
print(i);//如果在java語言中,則無效
}
JavaScript引擎在執(zhí)行每個函數(shù)實例時,都會創(chuàng)建一個
執(zhí)行環(huán)境(execution context)。
執(zhí)行環(huán)境 中包含一個調(diào)用對象(call object), 調(diào)用對
象是一個scriptObject結(jié)構(gòu)
(“運行期上下文”),用來保存內(nèi)部變量表varDecls、
內(nèi)嵌函數(shù)表 funDecls、父級引用列表upvalue等
語法分析 結(jié)構(gòu)(注意:varDecls
和funDecls等信息是在語法分析階段就已經(jīng)得到,并
保存在語法樹中。
函數(shù)實例執(zhí)行時,會將這些信息從語法樹復制到
scriptObject上)。
scriptObject是與函數(shù)相關的一套靜態(tài)系統(tǒng),與函數(shù)實
例的生命周期
保持一致,函數(shù)執(zhí)行完畢,該對象銷毀。
JavaScript引擎通過作用域鏈(scope chain)把多個
嵌套的作用域串連在一起,并借助這個鏈條幫助JavaScript
解釋器檢索變量的值 。這個作用域鏈相當于一個索引表,
并通過編號來存 儲它們的嵌套關系。當JavaScript解釋器
檢索變量的值,會按著這個索引編號進行
快速查找,直到找到全局對象(global object)為止,如
果沒有找到值,則傳遞一個特殊的undefined值。
案例分析:
var scope = "global";
scopeTest();
function scopeTest(){
alert(scope);
var scope = "local";
alert(scope);
}
打印結(jié)果:undefined,local;
分析:省略詞法分析等過程...執(zhí)行遇到函數(shù)調(diào)用scopeTest(),
創(chuàng)建一個調(diào)用對象(運行期上下文,函數(shù)執(zhí)行完畢,該對象銷毀)
,構(gòu)造它的作用域鏈時,搜索函數(shù)中用var聲明的變量放入該鏈(
在語法分析階段就已經(jīng)得到放在語法樹中,此時只是拷貝過來)
,因此scope在整個函數(shù)
scopeTest內(nèi)都是可見的(從函數(shù)體的第一行到最后一行)。雖
然函數(shù)scopeTest的作用域鏈上有全局對象,自然能夠訪問
到全局的scope, 但尋找變量時會沿著自身作用域鏈向上
逐個找,因此首先找到自己的scope:undefined。
如果函數(shù)引用了外部變量的值,則JavaScript引擎會為該函數(shù)創(chuàng)建
一個閉包體(closure),閉包體是一個完全封閉和獨立的作用域,
它不會在函數(shù)調(diào)用完畢后就被JavaScript引擎當做垃圾進行回收。
閉包體可以長期存在,因此開發(fā)人員常把閉包體當做內(nèi)存中的蓄水
池,專門用來長期保存變量的值。只有當閉包體的外部引用被全部
設置為null值時,該閉包才會被回收。當然,也容易引發(fā)垃圾泛濫,
甚至出現(xiàn)內(nèi)存外溢的現(xiàn)象。