function DemoFunction(){ this.init = function(){ var func = (function(va){ this.va = va; return function(){ va += this.va; return va; } })(function(va1, va2){ var va3 = va1 + va2; return va1; }(1,2)); console.log(func(20)); this.func = func; console.log(this.func(100)); } } var a = new DemoFunction(); a.init();
首先咱們得有以下幾個概念:html
執行上下文:每次當控制器轉到ECMAScript可執行代碼時,即會進入一個可執行上下文,參考文獻:深刻理解JavaScript系列(11):執行上下文(Execution Contexts)瀏覽器
this:this的建立是在 「進入執行上下文」 時建立的,在代碼執行過程當中是不可變的,參考文獻:深刻理解JavaScript系列(13):This? Yes,this!閉包
自執行函數:準確來講應該叫:當即調用函數表達式。由於他聲明後即執行,參考文獻:深刻理解JavaScript系列(4):當即調用的函數表達式函數
詳細解釋此段代碼this
這是代碼的重點,第一層代碼能夠縮減爲以下:prototype
function DemoFunction(){ this.init = function(){ //省略代碼.... } }
表示爲DemoFunction的實例提供init方法(聲明:此處有誤導成份,方法應儘量放在原型連接上,也就是prototype上。),對外公開的接口。code
var func = (function(va){ this.va = va; return function(){ va += this.va; return va; } })(/*省略代碼...*/); //省略代碼....
上面代碼介紹:htm
首先定義了一個當即執行函數,並把此函數的執行結果賦值給func。對象
須要注意當即執行函數中this.va=va這行代碼,因爲當即執行函數沒有調用者,因此在進入可執行上下文時,this會被賦值爲Global(瀏覽器中爲window對象)。blog
更須要注意當即執行函數,返回的是一個匿名函數,也是一個閉包,在這裏必定要注意一個問題:this是在進入可執行上下文時建立的。
var func = (function(va){ this.va = va; return function(){ va += this.va; return va; } })(function(va1, va2){ var va3 = va1 + va2; return va1; }(1,2)); //省略代碼....
va的實際參數是一個自執行匿名函數,這個匿名函數接受了兩個參數va1,va2,但只返回了va1。以此爲據,那麼能夠肯定va的值也就爲1。接着就執行this.va=va這句代碼,因爲當前this爲window,因此參數va的值被賦值到了window的一個叫va的屬性上。
var func = (function(va){ this.va = va; return function(){ va += this.va; return va; } })(function(va1, va2){ var va3 = va1 + va2; return va1; }(1,2)); console.log(func(20)); this.func = func; console.log(this.func(100)); }
結果分析:
第一個console.log輸出的是func(20),這裏必定要注意調用者是沒有具體指定的,此時默認的就是Global(也就是widnow對象),所以輸出爲:2
第二個console.log輸出的是this.func(100),能夠看到this.func與func是指向同一個函數的引用,但此時的調用者則指定爲this,也就是當前對象的實例,所以輸出爲:NaN。緣由:this(當前對象的實例)做爲調用者,在func的函數中va += this.va這句代碼中的this是指向當前對象的實例,但當前對象的實例上是沒有va屬性的。可是va是有值的,當前值爲2了。是由於閉包把va值存到內存中了。那麼如何讓第二次獲得的值也是2呢,結果很簡單,以下:
function DemoFunction(){ this.va = 0; this.init = function(){ var func = (function(va){ this.va = va; return function(){ va += this.va; return va; } })(function(va1, va2){ var va3 = va1 + va2; return va1; }(1,2)); console.log(func(20)); this.func = func; console.log(this.func(100)); } } var a = new DemoFunction(); a.init();