淺談 JS 里 一句代碼是怎么運行的及其編譯原理
- 用第一性原理來推匯出來
前言
可能有很多小伙伴在JS代碼運行中只知道一些基本的,像代碼是逐行運行的、分為編譯階段和執行階段,當問到代碼是怎么運行的 和 JS代碼運行的編譯原理時,有的小伙伴就可能理解不是很全面了,這也是很多大廠里面試所會問的問題,下面我會為大家詳細的講解一下在JS中代碼是怎樣運行的,它的編譯原理是什么,
代碼運行
首先我們在js檔案中輸入showName();來看看它的運行結果是什么
輸入:
showName();
輸出:
ReferenceError: showName is not defined
哎,系統報錯說 未定義showName() 為什么是這樣呢?
我們都知道JS是代碼檔案,匯入記憶體,申請變數空間,在執行中,由于計算機在記憶體中沒有找到showName,所以給出undefined,
然后我們再在后面輸入console.log( myName);又會有怎樣的結果呢?
showName();
console.log(myName);
結果:
ReferenceError: showName is not defined
哎,你會發現跟之前沒有區別,為什么是這樣呢?
答案顯然跟上面是一樣的,
那么為什么計算會知道showName有沒有被定義呢?
這就要知道任何代碼都分為編譯階段 和 執行階段,計算機在編譯階段的時候就會告訴你showName沒有被定義,編譯階段可以檢測出代碼中那些最嚴重的的錯誤,在執行階段中往往會終止在最開始的問題的地方,所以代碼是逐行運行的,
接下來我們在輸入:
console.log(myName);// 執行陳述句
var myName = '極客';// 賦值陳述句,執行階段
結果會是什么呢?
undefined
咦,你會發現沒有報錯,只有一個undefined,為什么沒有報錯,怎么沒有輸出‘極客’呢?怎么只有一個undefined呢?
那就要引入 變數提升的知識點了
在編譯階段,JS中變數的宣告會被提升到當前作用域的最頂端(全域作用域)構建一個scope 物件,會把所有的變數放進去并整理,給當前代碼一個運行環境(執行背景關系)
console.log(myName)是一條執行陳述句,所以在編譯階段,myName會被提升到scope中去,在執行階段找得到myName,所以沒有報錯,只有undefined,
其實它實際執行順序是這樣的:
var myName;// 編譯階段
console.log(myName);
myName = '極客';// 執行階段
又會有人提問了,如果按照這個執行順序的話,為什么輸出結果不是null呢?
這是因為在js中,js的型別是由值決定的,
現在相信大家對普通變數宣告的變數提升有了一定的了解,那么我們接下來了解一下函式的變數提升,看看這兩者的區別,
函式的變數提升
接下來看一下下面的例子:
showName();
console.log(myname);
var myname = '極客時間';
function showName(){ // 函式與普通變數宣告來做對比 函式可以來呼叫
console.log('函式showName被執行了');
}
你覺得它會輸出什么呢?是不是相當于這樣執行:
var myname;
showName();
console.log(myname);
myname = '極客時間';
function showName(){ // 函式與普通變數宣告來做對比 函式可以來呼叫
console.log('函式showName被執行了');
}
然后輸出:
undefined
undefined
或者是它會報錯?其實都不然
正確結果是:
函式showName被執行了
undefined
為什么是這個結果呢?

因為這是一個完整的函式宣告,函式在js中是排位第一的,在js中也被叫作“一等公民”,函式跟變數不同的地方在與函式擁有再次創建執行背景關系的權利,為什么會有這種特權呢?因為函式在會創建一個函式作用域(區域作用域)
那么,大家再來看下面代碼:
showName();
console.log(myname);
var myname = '極客時間';
// 函式運算式
var showName = function() {
console.log('函式showName被執行了');
}
這應該輸出什么呢?
輸出:
TypeError: showName is not a function
怎么會報錯呢?
一定會報錯!!!JS的型別是由值決定的,由于編譯階段var showName變數提升到了最頂端,并且賦予了一個undefined,而showName();是一個函式呼叫,與作用域中的showName不匹配,所以它一定會報錯,大家可以看圖再理解一下,


總結
- 代碼一定是逐行運行的
- 分為編譯階段和執行階段,有先后順序
- 區分哪些代碼是在編譯階段運行的,比如變數宣告
- 作用域的概念 scope是一個物件 目的是去存放當前代碼,去實作等下執行背景關系中的所有變數的參考
- 在執行代碼時,會涉及到變數的查找
var myName; //編譯階段 JS變數的型別由值決定 undefined
myName = ‘yjf’; //執行階段 - 所謂的變數提升,是指在JS代碼執行中,JavaScript引擎中(v8)把變數的宣告部分和函式的宣告部分提升到代碼開頭的行為,變數提升后,會給變數設定默認值undefined,
思考
showName()
var showName = funcation() {
console.log(2);
}
funcation showName() {
console.log(1);
}
showName()
- 以執行背景關系環境、編譯階段、執行階段,為什么答案是這個?
- 變數提升的圖畫出來
答案:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/277029.html
標籤:其他
上一篇:Nmap工具淺談
下一篇:按鍵——濾波消抖電路
