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();
首先我們得有如下幾個概念:
執行上下文:每次當控制器轉到ECMAScript可執行程式碼時,即會進入一個可執行上下文,參考文獻:深入理解JavaScript系列(11):執行上下文(Execution Contexts)
this:this的建立是在 “進入執行上下文” 時建立的,在程式碼執行過程中是不可變的,參考文獻:深入理解JavaScript系列(13):This? Yes,this!
自執行函式:準確來說應該叫:立即呼叫函式表示式。因為他宣告後即執行,參考文獻:深入理解JavaScript系列(4):立即呼叫的函式表示式
詳細解釋此段程式碼
一、首先看DemoFunction的建構函式
這是程式碼的重點,第一層程式碼可以縮減為如下:
function DemoFunction(){
this.init = function(){
//省略程式碼....
}
}
表示為DemoFunction的例項提供init方法(宣告:此處有誤導成份,方法應儘可能放在原型連結上,也就是prototype上。),對外公開的介面。
二、在init方法中,再次省略程式碼如下:
var func = (function(va){
this.va = va;
return function(){
va += this.va;
return va;
}
})(/*省略程式碼...*/);
//省略程式碼....
上面程式碼介紹:
首先定義了一個立即執行函式,並把此函式的執行結果賦值給func。
需要注意立即執行函式中this.va=va這行程式碼,由於立即執行函式沒有呼叫者,所以在進入可執行上下文時,this會被賦值為Global(瀏覽器中為window物件)。
更需要注意立即執行函式,返回的是一個匿名函式,也是一個閉包,在這裡一定要注意一個問題:this是在進入可執行上下文時建立的。
三、在init方法中,注意如下程式碼:
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的屬性上。
四、在init方法中,加上輸出語句:
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();