導航:首頁 > 源碼編譯 > Js的編譯機制vo

Js的編譯機制vo

發布時間:2022-08-09 10:27:55

『壹』 js代碼嵌套問題,為什麼外層定義的變數內層不能使用

是這樣的,在js的解釋器(編譯機制)里的規則是這樣的

在作用域中的變數聲明和方法聲明都會唄編譯器在編譯的時候,

給強制挪到第一行,在開始執行,並且變數的默認值都是 `undefined`

比如:

(function(){
//這是一個獨立作用域
vari=0;
vara=1;
alert(i+a);
})();

經過編譯後的代碼可能會類似這樣

(function(){
vari,a;//變數的聲明會挪到首行,並且變數默認賦值為`undefined`
i=0;
a=1;
alert(i+a);
})();

也會有這種情況

(function(){
alert(a);
test();
vara=1;
functiontest(){
alert('testfn');
}
})();

編譯後的代碼:

(function(){
vara;
functiontest(){//方法會直接挪到代碼前
alert('testfn');
}
alert(a);
test();
a=1;
})();

所以你會發現,定義的方法,在代碼的任何位置都可以調用,就是這個原因,因為編譯後的代碼,不管你的方法定義在那裡,都會幫你挪到首行


另外,你那裡的變數,作用域的問題的規則是這樣的

如果同名的變數,那麼局部作用域的變數優先於外部變數

vara=1;//這是一個外部定義的變數
(function(){
alert(a);
vara=2;//在這里,又使用`var`聲明了一次`a`,
//那麼這個變數就會覆蓋在外面定義的變數`a`
})();

編譯後的結果將是這樣

vara;
a=1;
(function(){
vara;//這里的a就會覆蓋外面的變數a,並且編譯器會默認賦值undefined
alert(a);//所以這里就會彈出undefined了
a=1;
})();


當人,如果內部沒有用`var`聲明這個變數,那麼外部作用域和內部的作用域就會使用同一個變數

比如這樣

vara=1;
(function(){
alert(a);//這樣這個方法在自己的作用域中無法找到變數`a`,就會去父作用域找變數`a`
//如果還沒找到,就在往父作用域中找,這樣直到找到為止
//或者一直找到global(全局作用域)還沒找到變數`a`,
//就會拋出一個異常(也就是報錯)'ReferenceError:`a`isnotdefined'
})();

『貳』 2015 nodejs還會火熱嗎

這段代碼的問題是在上面兩個語句之間,在整個數據查詢的過程中,當前程序進程往往只是在等待結果的返回.這就造成了進程的阻塞.對於高並發,I/O密集行的網路應用中,一方面進程很長時間處於等待狀態,一方面為了應付新的請求不斷的增加新的進程.這樣的浪費會導致系統支持QPS遠遠小於後端數據服務能夠支撐的QPS,成為系統的瓶頸.而且這樣的系統也特別容易被慢鏈接攻擊(客戶端故意不接收或減緩接收數據,加長進程等待時間).
如何解決阻塞問題
解決這個問題的辦法是,建立一種事件機制,發起查詢請求之後,立即將進程交出,當數據返回後觸發事件,再繼續處理數據:

Js代碼
//定義如何後續數據處理函數
function onDataLoad(name){
output("name");
}
//發起數據請求,同時指定數據返回後的回調函數
db.query("select name from persons where id=1",onDataLoad);

我們看到按照這個思路解決阻塞問題,首先我們要提供一套高效的非同步事件調度機制.而主要用於處理瀏覽器端的各種交互事件的javaScript.相對於其他語言,至少有兩個關鍵點特別適合完成這個任務.
為什麼JS適合解決阻塞問題
首先JavaScript是一種函數式編程語言,函數編程語言最重要的數學基礎是λ演算(lambda calculus) -- 即函數可以接受函數當作輸入(參數)和輸出(返回值).
函數可以作為其他函數的參數輸入的這個特性,使得為事件指定回調函數變得很容易.特別是JavaScript還支持匿名函數.通過匿名函數的輔助,之前的代碼可以進行簡寫如下.

Js代碼
db.query("select name from persons where id=1",function(name){
output(name);
});

還有一個關鍵問題是,非同步回調的運行上下文保持(稱狀態保持),我看一段代碼來說明何為狀態保持.

Js代碼
//傳統同步寫法:將查詢和結果列印抽象為一個方法
function main(){
var id = "1";
var name = db.query("select name from persons where id=" + id);
output("person id:" + id + ", name:" + name);
}
main();

前面的寫法在傳統的阻塞是編程中非常常見,但接下來進行非同步改寫時會遇到一些困擾.

Js代碼
//非同步寫法:
function main(){
var id = "1";
db.query("select name from persons where id=" + id,function(name){
output("person id:" + id + ", name:" + name);//n秒後數據返回後執行回調
});
}
main();

細心的同學可以注意到,當等待了n秒數據查詢結果返回後執行回調時.回調函數中卻仍然使用了main函數的局部變數"id",而"id"已經在n秒前走出了其作用域,這是為什麼呢?熟悉JavaScript的同學會淡然告訴您:"這是閉包(closures)~".
其實在復雜的應用中,我們一定會遇到這類場景.即在函數運行時需要訪問函數定義時的上下文數據(注意:一定要區分函數定義時和函數運行時這樣的字眼和其代表的意義,不然很快就會糊塗).而在非同步編程中,函數的定義和運行又分處不同的時間段,那麼保持上下文的問題變得更加突出了.
在這個例子中,db.query作為一個公共的資料庫查詢方法,把"id"這個業務數據傳入給db.query,交由其保存是不太合適的.但聰明的同學們可以抽象一下,讓db.query再支持一個需要保持狀態的數據對象傳入,當數據查詢完畢後可以把這些狀態數據原封不動的回傳.如下:

Js代碼
function main(){
var id = "1";
var currentState = new Object();
currentState.person_id = id;
db.query("select name from persons where id=" + id, function(name,state){
output("person id:" + state.person_id + ", name:" + name);
},currentState);//注意currentState是db.query的第三個參數
}
main();

記住這種重要的思路,我們再看看是否還能進一步的抽象?可以的,不過接下的動作之前,我們先要了解在JavaScript中一個函數也是一個對象.一個函數實例fn除了具備可函數體的定義之外,仍然可以在這個函數對象實例之上擴展屬性,如fn.a=1;受到這個啟發我們嘗試把需要保持的狀態直接綁定到函數實例上.

Js代碼
function main(){
var id = "1";
var currentState = new Object();
currentState.person_id = id;
function onDataLoad(name){
output("person id:" + onDataLoad.state.person_id + ", name:" + name);
}
onDataLoad.state = currentState ;//為函數指定state屬性,用於保持狀態
db.query("select name from persons where id=" + id, onDataLoad);
}

我們做了什麼?生成了currentState對象,然後在函數onDataLoad定義時,將currentState綁定給onDataLoad這個函數實例.那麼在onDataLoad運行時,就可以拿到定義時的state對象了.而閉包就是內置了這個過程而已.

在每個函數運行時,都有一個運行時對象稱為Execution context,它包含如下variable object(VO,變數對象),scope chain(作用域鏈)和thisValue三部分.詳見ECMA-262 JavaScript. The Core

其中變數對象VO,包含了所有局部變數的引用.對於main函數,局部變數"id"存儲在VO.id內.看起來用VO來代替我們的currentSate最合適了.但main函數還可能嵌套在其他函數之內,所以我們需要ScopeChain,它是一個包含當前運行函數VO和其所有父函數scope的數組.
所以在這個例子中,在onDataLoad函數定義時,就為默認為其綁定了一個[[scope]]屬性指向其父函數的ExecutionContext的ScopeChain.而當函數onDataLoad執行時,就可以通過[[scope]]屬性來訪問父函數的VO對象來找到id,如果父函數的VO中沒有id這個屬性,就再繼續向上查找其祖先的VO對象,直到找到id這個屬性或到達最外層返回undefined.也正是因為這個引用,造成VO的引用計數不為0,在走出作用域時,才不會被垃圾回收.
很多人覺得閉包很難理解,其實我們只要能明確需要區分函數定義和函數運行這兩個時機,記住閉包讓函數在運行時能夠訪問到函數定義時的所處作用域內的所有變數.或者說函數定義時能訪問到什麼變數,那麼在函數運行時通過相同的變數名一樣能訪問到.

關於狀態保持是本文的重點,在我看到的多數NodeJS的介紹文章,並沒有詳解這里,我們只是知道了要解決阻塞問題,但是JavaScript解決阻塞問題的優勢在哪裡,作為一個前端開發,我想有必要詳細解釋一下.

其實說到狀態保持還有一個類似的場景,比如用戶從A頁面提交表單到B頁面,如果提交數據校驗不通過,則需要返回A頁面,同時保持用戶在A頁面填寫的內容並提示用戶修改不對的地方.從提交到返回顯示這也是一個包含網路交互的非同步過程.傳統網頁,用戶的狀態通過請求傳遞到服務端,交由後端狀態保持(類似交給db.query的currentSate).而使用Ajax的網頁,因為並未離開原頁面,那麼服務端只要負責校驗用戶提交的數據是否正確即可,發送錯誤,返回錯誤處相關信息即可,這就是所謂前端狀態保持.可以看到這個場景里邊服務端做的事情變少了,變純粹了.正如我們的例子中db.query不再存儲轉發第三個state參數,變得更輕量.

我們看到通過JavaScript函數式語言特性,匿名函數支持和閉包很漂亮的解決了同步編程到非同步編程轉化過程中遇到的一系列最重要的問題.但JavaScript是否就是最好的?這就要回答我們引用新技術時需要考慮的最後一個問題了
使用NodeJS是否帶來額外的困擾,如何解決
性能真的是最好么?不用比較我們也可以得到結論NodeJS,做無阻塞編程性能較難做到極致.何為極致,處理一個請求需要佔用多少內存,多少cpu資源,多少帶寬,如果有浪費就不是極致.阻塞式編程浪費了大量進程資源只是在等待,導致大量內存和cpu的浪費.NodeJs好很多,但也正是因為一些閉包等JS內建機制也會導致資源的浪費,看下面的代碼

Js代碼
function main(){
var id = "1";
var str = "..."; //這里存儲一個2M的字元串
db.query("select name from persons where id=" + id,function(name){
output("person id:" + id + ", name:" + name);//n秒後數據返回後執行回調
});
}
main();

直到數據查詢完成,變數str所使用的2M內存不會被釋放,而str保持下去可能並沒有意義.前面已經解釋過閉包的原理,閉包並沒有智能到只包起來今後可能被訪問到的對象.即使不了解閉包的原理,也可以通過一段簡單腳本驗證這點:

Js代碼
function main(){
var id = "1";
var str = "..."; //這里存儲一個2M的字元串
window.setTimeout(function(){
debugger; //我們在這里設置斷點
},10000)
}
main();

我們在回調函數當中只設置一個斷點,並不指明我們要訪問哪個變數.然後我們在控制台監視一下,id和str都是可以拿到的.(此處結論不嚴謹,各種新瀏覽器已經就此做了相關優化,詳見評論2樓,特別是2樓給出的詳細測試報告的連接)
所以我來不負責任的預測一下,性能極端苛刻的場景,無阻塞是未來,但無阻塞發展下去,或者有更輕量的腳本引擎產生(lua?),或者V8JS引擎可能要調整可以disable閉包,或者我們可以通過給JS開發靜態編譯器在代碼發布前優化我們的代碼.

我之前談到過JS靜態編譯器:"如果給JS代碼發布正式使用前增加一個編譯步驟,我們能做些什麼",動態語言的實時編譯系統只完成了靜態語言編譯中的將代碼轉化為位元組碼的過程,而靜態語言編譯器的額外工作,如介面校驗,全局性能優化等待.所以JS也需要一個靜態的編譯器來完成這些功能,Google利用ClouserComplier提供了系列編譯指令,讓JS更好的實現OO編程,我來利用靜態編譯器解決一些JS做細粒度模塊化引入的性能方面的問題.而老趙最近的項目JSCEX,則也是利用JS發布前的編譯環節重點解決非同步編程的代碼復雜度問題.
我們習慣於阻塞式編程的寫法,切換到非同步模式編程,往往對於太多多層次的callback嵌套弄得不知所措.所以老趙開發的JS靜態編譯器,借鑒F#的Computation Expressions,讓大家遵守一些小的約定後,能夠仍然保持同步編程的寫法,寫完的代碼通過JSCEX編譯為非同步回調式的代碼再交給JS引擎執行.
如果這個項目足夠好用,那就也解決了一個使用NodeJS這種新技術,卻加大編程復雜度這個額外引入的困擾.甚至可以沿著這個思路,在靜態編譯階段優化內存使用.

NodeJS還要解決什麼問題
說了這么多,無阻塞編程要做的還遠不止這些.首先需要一個高效的JS引擎,高效的事件池和線程池.另外幾乎所有和NodeJS交互的傳統模塊如文件系統,數據訪問,HTTP解析,DNS解析都是阻塞式的,都需要額外改造.
正是NodeJS作者極其團隊,認清問題問題以及JS解決這些問題方面的優勢.基於高效的V8 JavaScript引擎,貢獻了大量的智慧和精力解決上述大部分問題後才有NodeJS橫空出世.
當前Node社區如此火熱,千餘開源的NodeJS模塊,活躍在WebFramework,WebSocket,RPC,模板引擎,數據抓取服務,圖形圖像幾乎所有工程領域.

『叄』 什麼是JS

Javascript簡稱js,js是一種腳本語言。

Javascript簡稱js,js是一種腳本語言,是不需要進行編譯的,也是瀏覽器中的一部分,經常用在web客戶端腳本語言,主要是用來給html增加動態功能。

一般情況下,html頁面主要是用於靜態內容的顯示,但是在實際中,頁面很少的靜態的,現在是網站都會有一些表單和幻燈片,這些都是使用js來進行交互,其實還有一些語言在可以編寫腳本,實際上都是js。

Javascript的特點:

js是面對對象的,我們可以創建對象和使用現有的對象。js是不需要編譯就能執行的腳本語言,並且是在運行中,直接進行解釋。
js是不需任何的操作系統,只要有瀏覽器支持就可以,並且同時支持多種瀏覽器運行。js對數據類型是不需要任何要求的,採用的方式是弱類型。

『肆』 為什麼JavaScript運行時不像Java那樣需要編譯是因為JavaScript沒有像Java那樣的運行環境么

因為JavaScript是一種圖形層語言,而java是伺服器端代碼.JavaScript要通過伺服器才能現實.

『伍』 js是按照代碼塊來進行編譯和執行的,代碼塊間相互獨立,但變數和方法共享對嗎

js沒有代碼塊的概念(在變數作用域方面而言)。
js的編譯和執行基本是按代碼順序,代碼塊間相互影響。
變數和方法在作用域內共享。

『陸』 js有什麼特點

1、js是一種解釋性腳本語言(代碼不進行預編譯

2、跨平台特性,在絕大多數瀏覽器的支持下,可以在多種平台下運行(如Windows、Linux、Mac、Android、iOS等)。

3、弱類型腳本語言

對使用的數據類型未做出嚴格的要求,可以進行類型轉換,簡單又靈活。

4、單線程,事件驅動

JavaScript對用戶的響應,是以事件驅動的方式進行的。在網頁(Web Page)中執行了某種操作所產生的動作,被稱為「事件」(Event)。例如按下滑鼠、移動窗口、選擇菜單等都可以被視為事件。當事件發生後,可能會引起相應的事件響應,執行某些對應的腳本,這種機制被稱為「事件驅動」。

5、面向對象

一種基於對象的腳本語言,這意味著JavaScript能運用其已經創建的對象。因此,許多功能可以來自於腳本環境中對象的方法與腳本的相互作用。

6、安全性

JavaScript是一種安全性語言,它不允許訪問本地的硬碟,並不能將數據存入到伺服器上,不允許對網路文檔進行修改和刪除,只能通過瀏覽器實現信息瀏覽或動態交互。從而有效地防止數據的丟失。



『柒』 Javascript 代碼(*.js文件)如何編譯

客戶端的JS是基於對象的解釋語言,基本上和HTML同一性質,都是通過BROWSER解釋的。哦,HTML不是沒有基於對象。
好像還有服務端的JS。

『捌』 javascript可以用某種手段編譯成一個二進制可執行文件嗎

你可以把腳本用二進制方式寫進圖片或者視頻里,但是這個東西對於網站的過濾來說,會變得很復雜。加入我在圖片里插入了惡意腳本,你還允許我上傳到伺服器。那伺服器就有可能被我通過那段惡意代碼控制。
你寫好一段js腳本,把它以二進制的方式添加到圖片里,圖片裡面的圖片類型要保留,然後加入/* xxxx */來注釋掉圖片內容。
在<script src=''><script>,src屬性可以指定圖片。

『玖』 請高手解釋下為什麼Javascript是一種解釋性語言,不需要進行編譯和構建.在看Jquery的書,有句話是這樣說的

解釋執行主要是針對編譯執行編譯執行來說的,C語言,java等靜態語言,寫好代碼後需要經過編譯器編譯,將源代碼編譯成別的代碼,比如機器碼,匯編等,解釋執行則不需要編譯過程,直接由解釋器解析並執行代碼。
javascript就屬於解釋執行,所以說他是一種解釋性語言。
但是,隨著技術的發展,越來越多的javascript引擎為了提高性能,也會對javascript進行一些編譯,所以也很難清楚的界定javascript到底是解釋執行還是編譯執行。所以也沒必要去深究,知道就行。

閱讀全文

與Js的編譯機制vo相關的資料

熱點內容
php數組中刪除元素 瀏覽:724
螢石雲伺服器視頻 瀏覽:269
防火牆配置伺服器熱備的虛擬地址 瀏覽:188
linux安裝xdm 瀏覽:736
java計算12 瀏覽:249
大金空調擺動式壓縮機 瀏覽:453
新的雲伺服器如何設置首頁 瀏覽:687
javastring字元位置 瀏覽:196
銀河麒麟字體庫存在哪個文件夾 瀏覽:957
魔獸加丁伺服器的航空叫什麼 瀏覽:152
花冠改裝案例哪個app多 瀏覽:515
成績單app哪個好用 瀏覽:140
北美程序員vs國內程序員 瀏覽:181
php解析xml文檔 瀏覽:121
石墨文檔APP怎麼橫屏 瀏覽:185
牆主鋼筋加密和非加密怎麼看 瀏覽:144
金山區文件夾封套定製 瀏覽:708
soho程序員 瀏覽:672
java位元組截取 瀏覽:526
php提交作業 瀏覽:816