js是單執行緒的語言,也是一門解析型語言,所以他有著屬於自己的一種執行方式,我們所說我預編譯就是js解析型語言的一種解釋。所以我要先給大家描述一下js的語言分析和同步概念。
在我們**執行的時候,我們的瀏覽器會先將js所有需要執行的**全面檢測一遍,目的是排除低階的語法錯誤,檢測到錯誤後,乙個乙個丟擲,而不是一下子全部丟擲,所以js是單執行緒,這也是一種程式設計上的同步。
什麼是js的同步呢?
同步:從上往下按順序執行的程式; 弊端:中間任何乙個程式出現問題,下面**乙個都不會執行就像山間小路,乙個不能走了,下面全堵住了
var a =10;
var b =20;
console.
log(a)
console.
log(c)
// c 沒有定義,所以報錯,下面的 console.log(b) 就不會執行
console.
log(b)
來我們來看一下執行結果
什麼是js的非同步呢?
非同步(多個出口):程式的執行順序是無序的。不會存在等待現象,誰快是先執行
就像高速公路,有多條線,但還是只有乙個出口
console.
log(a)
var a =
10;
那麼他的輸出過結果呢?讓我們也來看一下
那麼大家有沒有一點奇怪呢?為什麼沒有報錯,我們上面說js是一門解析型語言,按道理來說是解析一行執行一行,那麼在我們輸出a的時候,a還是沒有定義的,所以他應該是會報錯的,這裡就要說到我們的預編譯環節了。
首先我們先來簡單的說一下變數提公升,它是屬於預編譯的一種,我先給大家混個眼熟,然後後面再給大家詳細講解。下面我先講解一下簡略版!這個是簡略版,大家且先看看:
將所有變數提公升當前作用域最頂端,賦值為undefined
將函式宣告提公升到作用域最頂端
當變數名與函式名重複的時候 , 變數賦值 會將函式本體覆蓋
console.
log(a)
;var a =10;
// 函式宣告
functiona(
) console.
log(a)
;
那麼下面的**再瀏覽器的解析中會這樣執行:
//首先將所有變數提公升當前作用域最頂端,賦值為undefined
var a = undefined;
// 將函式宣告提公升到作用域最頂端
functiona(
)// 當變數名與函式名重複的時候 , 變數賦值 會將函式本體覆蓋
console.
log(a)
;//所以a的就從一開始的undefined,變成 function a (){}
a =10;
console.
log(a)
;// 因為值賦是不會有提公升效果,所以最後執行賦值 a = 10
這樣是否就可以解決大家的困惑了呢?
我來總結一下那麼就是,①變數宣告提公升 ②函式宣告,如果有重名的就將其覆蓋,說到這裡我們就可以解決大部分基礎性問題了,但是我們講了就要將其講的透徹,他為什麼會是這樣的呢?
下面我就為大家來詳細講解預編譯!
預編譯存在於函式執行的前一刻!記住了,是函式執行的前一刻,大家先別去想上面的**,先記住我的這句話,因為上面的**講解是存在問題的,僅僅是為了讓大家了解一下什麼叫做變數提公升,函式宣告提公升 。
首先大家先看一下這四句話:
預編譯存在於函式執行的前一刻!
1 生成乙個ao 物件
2 將函式體中所有變數宣告和形參,作為ao物件的屬性名,提公升到作用域的最頂端,值為undefined
3 將實參值和形參相統一
4 在函式體中,找函式宣告,函式體賦予值(只有函式宣告才會提公升,表示式不會!!)
function
fun(x, y)
console.
log(a)
console.
log(b)
console.
log(x)
console.
log(y)
console.
log(c)
}fun(1,2)
我們看到fun()執行,也就是函式執行,那麼就再fun執行的前一刻會生成乙個ao物件(四句話的第一句)
所以ao物件再次變化
var a = undefined;
// 不變
var b = undefined;
// 不變
var x =1;
// 不變
var y =2;
// 不變
varc
=functionc(
)當所有的函式宣告找到,並且賦完值,那麼我們的預編譯的ao物件就執行完畢了
}
所以我們再來**上面的**:
function
fun(x, y)
}fun(1
,2)他就會變成:
function
fun(x, y)
// 因為var和函式表示式已經提公升了,但賦值沒有提公升,所以就變成下面這樣
console.
log(a)
// undefined
console.
log(b)
// undefined
console.
log(x)
// 1
console.
log(y)
// 2
console.
log(c)
// function c() {}
a =0;
b =0;
console.
log(a)
// 0
console.
log(b)
// 0
console.
log(x)
// 1
console.
log(y)
// 2
console.
log(c)
//function c() {}
}fun(1,2)
這樣就是預編譯的結束和**的執行的過程了,那麼我們再來講一下最上面的**:
console.
log(a)
;var a =10;
// 函式宣告
functiona(
) console.
log(a)
;
大家也可以將其看成乙個大的預編譯過程也就是go物件生成的過程流程:
第一步:生成乙個go物件
go{}
第二步:分析變數:go物件內容
go第三步:分析函宣告: go 如下
go(a:function a() {})
因為少了形參所以比上面的ao物件預編譯要少一步,所以如果大家僅僅把預編譯當成 變數提公升,函式宣告提公升 是明顯是不足夠的!!
希望大家看了之後有所感悟,並附上一道題,當大夥看完後可以自己去聯絡一番:
console.
log(a)
function
fun(a, b)if(
false
) console.
log(a)bb(
) console.
log(a)
}var a =
100fun(10
,20) console.
log(a)
js的單執行緒和預編譯是什麼?
js是單執行緒的語言,也是一門解析型語言,所以他有著屬於自己的一種執行方式,我們所說我預編譯就是js解析型語言的一種解釋。在我們 執行的時候,我們的瀏覽器會先將js所有需要執行的 全面檢測一遍,目的是排除低階的語法錯誤,檢測到錯誤後,乙個乙個丟擲,而不是一下子全部丟擲,所以js是單執行緒,這也是一種...
js的單執行緒和預編譯是什麼?
js是單執行緒的語言,也是一門解析型語言,所以他有著屬於自己的一種執行方式,我們所說我預編譯就是js解析型語言的一種解釋。語言分析 在我們 執行的時候,我們的瀏覽器會先將js所有需要執行的 全面檢測一遍,目的是排除低階的語法錯誤,檢測到錯誤後,乙個乙個丟擲,而不是一下子全部丟擲,所以js是單執行緒,...
JS非同步和單執行緒舉例
js 需要非同步的根本原因是 js 是單執行緒運 的,即在同 時間只能做 件事,不能 個 ajax 請求由於 絡 較慢,請求需要 5 秒鐘。如果是同步,這 5 秒鐘 就卡死在這 啥也做不了了。非同步的話,就好很多了,5 秒等待就等待了,其他事情不耽誤做,於那 5 秒鐘等待是 速太慢,不是因為 js ...