#hello,JS:03-02 聲明提前和立即執(zhí)行函數(shù)

一、聲明提前

1、變量聲明提前——變量提升

可參照這里的描述:

#hello,JS:01數(shù)據(jù)類型、運算符、運算符優(yōu)先級

//先輸出a,再聲明
var a=3 
console.log(a) //undefined  
var a=3

再如:

console.log(a)//undefined 
console.log(b)  //報錯 
 var a=3  

為什么console.log(a)輸出undefined,而console.log(b) 則會報錯呢?
出現(xiàn)這樣的情況是為什么?實際上JS引擎在一行行執(zhí)行代碼的時候,有一些默認(rèn)的運行我們并不知道,即:

var a   //undefined,變量a已經(jīng)前置聲明,則結(jié)果為undefined console.log(a) //undefined 
console.log(b) //報錯,沒有變量b,引用失敗 
a=3  

最后是:變量的聲明前置的完整運行:

var a     //undefined,已經(jīng)前置聲明為undefined 
console.log(a)     //undefined
 a=3 
console.log(a)  
--> undefined 3

2、函數(shù)的聲明前置

先看這段代碼:

sum(5,3) //放在任何的地方,但是只是一個函數(shù)值,并沒有打印這個函數(shù)出來
function sum(a,b){
    return a+b
}

設(shè)置兩種看兩種執(zhí)行結(jié)果:


image

看代碼,不是沒有任何的變量聲明?為什么就可以使用函數(shù)輸出結(jié)果?這是因為函數(shù)所執(zhí)行的JS引擎默認(rèn)操作與變量聲明前置機制是類似。
相當(dāng)于:包含變量數(shù)據(jù)的function函數(shù)前置,即以上代碼等同于

function  sum(a,b){ 
            return a+b
    }  
      sum(5,3) 
 //直接返回8

3、函數(shù)表達(dá)式的聲明前置

還是先看代碼:

fn()
var fn = function(){
    console.log('fn...')
}
//報錯,直接說fn不是一個函數(shù)

這里,function函數(shù)是一個變量,相當(dāng)于把一個數(shù)字賦值給fn,而這個function函數(shù)表達(dá)式,事實上也是有一個聲明前置的,即:

var fn   //undefined 
 fn()    //此為函數(shù),會執(zhí)行,但是如果是undefined(),這種是不成立,即報錯
 fn =  function(){ 
          console.log('fn...') 
 }

那么原始代碼是怎么執(zhí)行的?
原始代碼:

fn()  
sum(3,4) 
var fn =  function(){ 
           console.log('fn...')
    }  
           function  sum(a,b){ 
          return a+b
  }

對于瀏覽器來說它做了什么:一個聲明前置:包括變量聲明前置和函數(shù)聲明前置

    var fn //變量聲明前置  
             function  sum(a,b){ 
             return a+b }  //函數(shù)聲明前置 
                 fn()  
                sum(3,4) 
                 fn =  function(){ 
                   console.log('fn...') 
         }

二、立刻執(zhí)行的函數(shù)表達(dá)式

注:關(guān)于js的語法規(guī)則如何體現(xiàn)?

1、先看下面這個代碼

              (function(){ console.log('wangxiaoqin')  })() 
 -->"wangxiaoqin"

先暫且不管它的結(jié)果如何產(chǎn)生。先了解一下JS的語法規(guī)則


image

按照這樣寫,為何只有function(){}單獨作為一個變量時,通過模仿語句a( );,function(){}();這個語句則會操作會報錯,這是為什么?

對于JS引擎來說不認(rèn)為是一個表達(dá)式,很像一個函數(shù)聲明,再加一個括號,即會報錯。那么如何讓這個語句正常賦值?直接將整個函數(shù)聲明加一個括號,即:

(function(){})()

由于作為運算符,括號和括號里的內(nèi)容組合為一個表達(dá)式。加上括號之后,會讓JS引擎認(rèn)為它是一個表達(dá)式(或引用類型),那么就符合了JS的語法規(guī)則。

總結(jié):
當(dāng)在一個函數(shù)聲明后加了圓括號(也是一種運算符)后運行的話,會報錯。因為這被認(rèn)為是語法錯誤。在JS中,以function開頭會被認(rèn)為是語句,而語句不應(yīng)該以圓括號結(jié)尾。所以此時可以選用的解決辦法是把整個語句用圓括號包起來。

2、那么剛才列舉的代碼:

(function(){ 
              console.log('wangxiaoqin')  })()
  -->"wangxiaoqin"  //即函數(shù)表達(dá)式,立刻去執(zhí)行它
     
//等同于  
var fn =  function(){

   }  
     fn()

這類型的函數(shù)表達(dá)式有什么用?這里涉及了函數(shù)中所對應(yīng)的作用域的概念,假設(shè)我們在這類函數(shù)里添加一個變量

          (function(){ 
              var a =3 console.log('wangxiaoqin') 
         })() 
          console.log(a)
//運行,后臺報錯,a是沒有被定義的。 
 //因為a變量是不被看到的,因為a在function函數(shù)的這個作用域里,與外界無關(guān)

3、立刻執(zhí)行函數(shù)的好處:

var fn=function(){}

相當(dāng)于

fn()===(函數(shù)表達(dá)式)()

() 作為一種運算符,用這種局部作用域的方式將函數(shù)引用包裹起來,形成一個立即執(zhí)行的表達(dá)式,好處在于:

A、函數(shù)不必再另外命名,避免了污染全局,不會在復(fù)雜頁面協(xié)作中造成錯亂;

B、實現(xiàn)一個作用域隔離,封裝外部無法讀取的私有變量;

C、避免命名沖突,符合js語法規(guī)則,并立刻執(zhí)行。

三、命名沖突

當(dāng)在同一個作用域內(nèi)定義了名字相同的變量和方法的話,會根據(jù)前置順序產(chǎn)生覆蓋

var fn =  3; 
 function  fn(){
} 
console.log(fn); 
 // 3

相當(dāng)于

var fn function  fn(){}  //覆蓋上面的 fn =  3  //重新賦值 console.log(fn)  //為函數(shù)

當(dāng)函數(shù)執(zhí)行有命名沖突的時候,可以認(rèn)為在還是內(nèi)部一開始有隱藏的聲明變量這個操作

function  fn(fn){
        console.log(fn); 
        var fn =  3; 
         console.log(fn); 
  }  
fn(10)  //10 3  

//等同于有一個默認(rèn)的var fn = arguments[0]的操作 

 function  fn(){  
            var fn = arguments[0] //1、將它先聲明前置,再賦值,再輸出
          console.log(fn);  
          var fn =  3;  //2、再賦值
           console.log(fn);  
       }  fn(10) 

 //10  3
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容