1. 程式人生 > >JavaScript中函數引用調用和函數直接調用的區別

JavaScript中函數引用調用和函數直接調用的區別

完全 var 堆內存 上下文環境 其中 多余 font 一個棧 詞匯

首先看下面的代碼:  

  var x = 1          var f1 = function( f ) {   var x = 2 ;   f( ‘ console.log( x ) ‘ )   }   var f2 = function( ) {   var x = 2 ;   eval( ‘ console.log( x ) ‘ )   }   f1( eval ) // 1   f2( )  // 2      eval 是一個 global 對象的內置函數,即便在 window 對象內,它也可以作為全局函數使用。   如果你對結果有疑問,那為了搞懂原因,需要了解 JavaScript 一個重要的知識點: 作用域 ,上下文環境
     很多書籍和大牛都會引用 上下文環境 這一概念,在我看來,上下文環境只是一種更加繁瑣的理解方式,甚至可以說是完全多余,如果去函數內尋找對應的屬性,只會發現一個包含scope關鍵字的屬性與作用域對應,在我看來,上下文環境只是一個被人為創造的詞匯,是為了便於他人理解而創建出來的抽象概念。   如果你接受了我上面的觀點,那作用域就同時囊括了上下文環境的特性,以下兩個觀點是理解作用域的關鍵:   第一,只有在函數執行的時候作用域才會生成,函數體內代碼未被執行的情況作用域是不會生效的;   第二,函數體所在處才是代碼執行的地方,依據第一個觀點,也即作用域生成的地方,是以此尋找上級作用域的起點。
  和其他強類型語言不同,JavaScript 能創造獨立作用域的方式還不夠豐富,函數聲明就是其中之一,在不考慮閉包等其他操作聯通作用域的情況下,同級作用域之間是絕對屏蔽的,即便是嵌套的作用域,也只允許子作用域向上查詢,父級作用域無法向下進入子作用域。   需要註意的是,不是子作用域的所有變量都可以向上去查詢,比如 this ,作為一門極其靈活而又混沌的語言,js不會允許這種情況發生,於是ES6這一標準提出了箭頭函數的概念,其作用是為 this 開辟一條通向上級作用域的特快通道,將 this 發射出去,這在本質上使得 JavaScript 的邏輯變得更加靈活了,不像其他語言具有較強的模式化屬性。   有點脫離主題了,說回為什麽兩者的輸出結果不一致,引用函數其實也是一個包裝過的概念,比如本例中的 f ,它的本質只是棧內存的索引地址,更重要的是這一地址指向的並不是存儲在堆內存裏的函數對象,而是指向另一個棧內存內的地址 eval ,eval 才是真正指向函數的指針,也可以直接將其理解為 eval 函數在棧內存內的唯一代言,毫無疑問,函數體內部才存在作用域,作用域的本質不過是附著了很多變量屬性的對象,需要註意的是,此例中並不是指 f1 和 f2 這兩個函數對象,而是指其引向的函數體 { } 這個對象。   如果你真正理解了上面我這段話,那麽也就不難理解結果不同的原因,f( ‘console.log( x ) ‘ )在執行的時候實際上還是去尋找 eval 所指向的作用域,而 eval 的上級作用域是全局作用域,其作用域內 x 的值是為 1 。   

JavaScript中函數引用調用和函數直接調用的區別