Js 預加載


開始 所有的測試,都是chrome瀏覽器。

  js本身是腳本語言,可以不經過編譯直接運行,但是在進入每一個<script>標簽,或者js文件的時候,這樣的情況下,瀏覽器會給js一個預編譯的過程。

這樣就有必要討論一下預編譯了。

  解析的狀態是首先引入一個代碼段,也就是之前提到的標簽或者文件。讀入整個代碼段,進行解析,解析的方式是遇到變量就聲明,

對變量聲明為undefined,對函數做標記,這個就是預解析,但是如果聲明了同名的函數,使用最后一個。變量都是undefied,只有觸發的時候,才會激活。

 

首先舉一個例子:

var a;
alert(a);
a = 10;
alert(a);

  預編譯的時候,將a設定為undefined。當執行第一個alert的是,會彈出undefined,因為此時a並沒有被賦值。

  運行到第二個的時候,彈出10.

 

alert(a);

   直接一句,瀏覽器會報錯。Uncaught ReferenceError: a is not defined。因為a並沒有被定義。這是肯定的,

 

但是:

alert(a);
a = 10;

  同樣是:Uncaught ReferenceError: a is not defined。這里能證明 如果不是var,那么a=10;雖然js也是定義了一個全局變量,

但是並沒有什么用,在預編譯階段,js無法在a=11之前引用它。並不知道a是什么,所以alert(a),並不能識別出來a的存在。證明js

解析是根據字符匹配來解析的,find到var的時候,才會定變量。盡管不是強類型的與語言,但是也無法在預編譯的階段,處理好不帶

var 關鍵字的全局變量。

  

在看函數的例子:

console.log(test);

function test() {
	console.log('haige');
}

  oK,沒有問題,會把函數打印出。

 

但是在看這個例子:

console.log(test);

var hg = function test() {
	console.log('haige');
}

  Uncaught ReferenceError: test is not defined。證明,你聲明了一個函數,給hg這個變量賦值,但是沒什么用,這是什么,是函數表達式。不是函數聲明!!!!

 

 修改一下,在看。

console.log(test);

var test = function test() {
	console.log('haige');
}

  undefined 為什么呢?因為test此時是個變量,不是函數。OK,比如這樣來看。

 

console.log(typeof test);

var test = function test() {
	console.log('haige');
}

  打印的是undefined。因為預編譯的時候,只是聲明了一個test變量,證明有,而不知道他是什么。所以無法判斷類型。

 

在舉一個例子:

var foo = 1;      
function bar() {    
  console.log(foo);  
    if (!foo) {      
        var foo = 10;   
    }      
    console.log(foo);      
}      

bar();

  猜猜看,還是挺有意思的, 第一個console.log()打印的是 undefined。為什么呢?在bar的這個函數作用域中,用var 聲明了一個foo的對象,但是,第一次使用時候,由於沒有賦值,

所以就出現了undefined的情況,在第二次打印的時候,就已經初始化了,函數執行,是觸發式執行方式,從上到下。

 

在舉一個更酷的例子

var a = 1;      
function b() {      
  console.log(a);  
    a = 10;      
  console.log(a);  
    return;      
    function a() {}  
}  

b();      
console.log(a);  

  思考一下,這個怎么玩出來,

 第一個打印,a 是一個 function a () {}

 第二個肯定就是10了。

 思考一下為什么,預編譯的時候,首先聲明了一個全局的a,這個a是一個對象,但是值是undefined,

執行b()函數的時候,給b做預編譯。此時,a是function,雖然有return,但是,編譯的時候肯定不是看到return就返回了,肯定都編譯了。

這樣a就變成了一個指向函數的變量。那么執行b()的時候,第一個打印就成function a() {}

執行第二打印的時候,a=10; 所以打印出10.

          變量內的賦值,實在執行的時候完成的,而不是聲明的時候。

 

這里在舉一個例子證明變量的聲明和賦值之間的關系。

a();
var a = function() {};
console.log(a);

  Uncaught TypeError: a is not a function.

在var聲明的變量中,在預編譯的過程中,都是undefined,當你執行var聲明的變量時,才開始觸發它所對應的值。

這里的a是變量,雖然給他賦值了函數的指針,但是並沒有什么用。因此,在var a = function 之前是無法解析的。

這個瀏覽器內核,按照變量的聲明方式解析,不按照類型解析。

 

 

 之后在思考一下函數之間的預編譯問題。

 

function hg(){   
  alert('hg');   
};   
  
hg();   
function hg(){   alert('wj'); }; hg();

 

  思考一下應該如何彈出,結果是兩個都是 wj。為什么呢?

很簡單,因為函數的解析第二個hg,將第一個覆蓋了,而hg是函數名,其實就是一個指針,那么hg將指針的指向,轉移到了第二個函數,導致的結果就是,

兩次執行,都執行的一個函數,這再次證明了預編譯的存在,因為預編譯,更改了第一個hg函數的指向。

 

 在看一個例子:

var ys = function(){
	alert('hg');
};   
ys();
ys = function(){ alert('wj'); }; ys();

  ys ()這個函數,其實是在預編譯的時候,是個變量,為什么呢?因為var,讓編譯器知道,他是一個變量,而類型,不是預編譯階段所關心的問題,

在執行第一個ys的時候,OK,根據上下文,ys被賦值為第一個函數。那么就是打印hg,

當執行第二個ys的是,這個時候,ys被賦值為第二個函數,就執行 wj。

 

 還有個例子,很酷的例子。兩段代碼,做個對比。

(1)

console.log(ys);    //function hg

function ys(){
	console.log('hg');  
}
ys();     // hg

 
var ys = function (){
	console.log('wj');
}   
ys();   //wj

  思考一下,很酷的,在看第二個。

(2)

 

console.log(ys);    //function hg

var ys = function (){
	console.log('wj');
}   
ys();   //wj

function ys(){
	console.log('hg');  
}
ys();    // wj

  這兩個例子做了對比,產生了幾個很有意思的觀點。

首先,如果函數和變量同名,那么,打印出來的就是一個函數,而不變量,這個跟你是否是var定義無關。即使是var定義的變量,依舊,把這個變量,類型變為函數。這個,下一個例子,會看得更清楚。

其次,由於變量的存在,所以是存在運行時動態的賦值的。所以,第一個才會出現ys更改的情況。

但是這里要注意一點,為什么兩次的第一個console.log,都打印hg呢?因為var a = function A() {}; 這個在預編譯的時候,是不執行的。所以,根本達不到更改ys指針的情況。

 

上面提到的下一個例子:

 

console.log(ys);    //function

function ys(){
	console.log('hg');  
}
console.log(ys);    //function   
var ys = 1;

 

  

 

  打印的是function 和 function 。為什么? 證明:上面提到的,當變量與函數同名的時候,預編譯的時候,函數會覆蓋變量。

console.log(ys);    //function

function ys(){
	console.log('hg');  
}
var ys = 1;
console.log(ys);    //1

  這種情況了,是因為ys在運行到ys=1是,被重新賦值了。

 

在變量實例化的過程中出現同名,優先級的關系是,聲明式函數》函數參數》變量

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM