js中的執行上下文,菜鳥入門基礎。


console.log(a); //Uncaught ReferenceError: a is not defined

因為沒有定義a所以報錯了。

var a = 52;
console.log(a); //52

有定義a,並且給a賦值了52所以打印a就是52。

console.log(a); //undefined
var a = 52; 

雖然有定義a但是打印卻在變量a的前面,那為什么不是報錯而是打印出來的是undefined?因為在js執行代碼之前,js會先獲取到所有的變量並且把這些變量放置到js代碼的頂部。(簡稱變量聲明提前)

實際上,上面的代碼是這樣執行的:

var a;
console.log(a);

所以代碼出來的就是undefined,那你是不是會疑問?我們給賦值給a的52到哪去了。雖然我前面說了js會事先獲取所有的變量並且將這些變量放置到頂部,但是變量的賦值並不會事先執行,也就是說,你在哪聲明的變量,這個變量的賦值就在哪執行。

var a;
console.log(a); //undefined

雖然聲明了但沒有賦值所有undefined

console.log(a); 
function a(){
  this.user = "追夢子";
}

為什么,可以事先就打印出函數a呢?因為函數的賦值在函數聲明的時候就已經賦值了,結合上面我說的變量提前,那是不是就可以理解這句話了?

當然這只是一種情況,還有一種情況,稍后說。

function a(){
  this.user = "追夢子";
}
console.log(a);

正常

a(); //Uncaught TypeError: a is not a function
var a = function(){
  console.log(52);
}

為什么現在又不行了?因為現在的函數已經賦值給了變量a,現在它的執行過程和變量一樣了,我們通常把這種函數賦值給變量的形式叫做函數表達式。

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

正常

if(false){
    var a = 1;
}
console.log(a); //undefined

之所以沒有報錯而是輸出了undefined是因為變量存在預解析的情況,又因為js沒有塊級作用域,所以最后代碼就成了這樣

var a;
if(false){
    a = 1;
}
console.log(a);

 

總結:

  函數分為:函數聲明和函數表達式。

  函數聲明--

function a(){
    alert("追夢子博客");
}

  函數表達式--

var a = function(){
    alert("追夢子");
}

  看似兩段相同的語句,它們的執行順序卻截然不同,函數聲明時的賦值行為是在函數創建的時候進行的,而函數表達式的賦值行為是在執行這句變量時進行的(因為它已經賦值給了變量所以我這里把它稱為變量)。

  不管是變量還是函數都會存在變量聲明提前。

來看看幾題有意思的js例題,加以理解。

  

var a = 1;
function b(){
    console.log(a); //undefined
    var a = 5;
}
b();

為什么打印的是undefined?

  我們先來看看它的解析過程:

var a = 1;
function b(){
    var a
    console.log(a); //undefined
    a = 5;
}
b();

  變量提前了,那為什么不打印全局變量1呢?如果你有這個問題我猜你應該是JavaScript的新朋友,那我建議你看我的上一篇文章:

什么是作用域鏈,什么是原型鏈,它們的區別,在js中它們具體指什么?

  在看完作用域鏈以后我相信你能夠看懂這個例子。

我們一起來看看另外一題比較有難度的js面試題:

  

var a = 1;      
function b() {      
    a = 120;      
    return;      
    function a() {}
}      
b();      
alert(a); //1;

  如果你看了上面一題我相信你應該有種不知所措的感覺,這里現在為什么又是1了呢?

我把執行過程的代碼寫出來我相信你就懂了。

  

var a = 1;      
function b() {
    var a;      
    a = 120;      
    return;      
    function a() {}
}      
b();      
alert(a); 

  如果你正在js的進階階段肯定更悶了,你肯定會想我們不是寫return了嗎?return后面的代碼不是不執行嗎?為什么這里卻影響了這段代碼?

  雖然return后面的代碼不會被執行,但是在js預解析的時候(變量提升的時候)還是會把return后面的變量提前,所以我們這段代碼因為變量提前所以函數里面的變量a就成了局部變量,因為函數外部是訪問不了函數內部的變量所以就輸出了1。

  另外提兩點,函數的arguments和函數名都是直接賦值的,也就是在這個函數解析的時候就會進行賦值。

  如果你還是不理解建議多看幾遍,另外如果你是js的新朋友一定要看什么是作用域鏈,什么是原型鏈,它們的區別,在js中它們具體指什么?這篇文章。


免責聲明!

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



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