1. 程式人生 > >Js New一個函式和直接呼叫的區別

Js New一個函式和直接呼叫的區別

        事情的起因:首先我要說的是上一篇部落格中我寫到的一句話:如果使用new關鍵字呼叫,那麼函式的 return 語句不再起作用,因為這時還回的是 this 物件。部落格發表以後,有網友評論中提到,當使用工廠方法的時候,最後return的是一個物件,而且也確實能夠使用這個返回的物件並訪問它的屬性。這就正好和上面說的有衝突了。當然我承認上面的那句話是我在蒐集資料的時候看到的這麼一句話。沒有經過我的驗證,當然我看到“咲臣”的評論之後我對這句話的正確性進行了詳細的驗證。首先大家看一下這個工廠模式建立js物件。

function Person(name,age){
	var o =new Object();
	o.name=name;
	o.age=age;
	o.getName=function(){
		alert(this.name);
	}
	return o;
}
var person1=new Person("hanyi",22);
alert(person1.name);

        執行結果:


在瀏覽器執行時監控person1的結果:


        首先討論一下第10行程式碼中new的必要性,這時候我們想要的結果應該是使person1為 Person (name,age)函式的返回結果,即物件O(Object)。當然為了保證正確性我們也做了驗證把這行程式碼改為 :                                                       

  var person1=Person("hanyi1",22);//(為了區別把字串稍微改動!)

        執行結果:


        在瀏覽器執行時監控person1的結果:


        為了進一步驗證:我們做以下修改:

function Person(name,age){
	this.a="123";
	var o =new Object();
	o.name=name;
	o.age=age;
	o.getName=function(){
		alert(this.name);
	}
	return o;
}
var person1=new Person("hanyi",22);
alert(person1.name +"   "+ person1.a);

即在函式Person(name,age)中新增this.name=name;然後執行看結果。

執行結果:


        在瀏覽器執行時監控person1的結果:


        這個例子可以清楚的看到,這裡即使使用了new關鍵字,但是Person(name,age)中的return還是起了作用。而且返回的明顯不是this物件,因為其中不包括a屬性的任何資訊。

        通過以上例子完全可以說明了上一篇部落格對於new關鍵字呼叫函式與普通方法呼叫函式的區別的解釋的錯誤性,到現在為止就證明了個錯誤的觀點,那什麼事正確的觀點呢。是不是如果一個函式中存在return語句,呼叫這個函式的時候使用new和不使用new返回的結果是一樣的呢?下面我們再來看看這個例子:

function Test() {  
  this.name = 'Test';  
  return function() { return true; }  
}  
  
var test = new Test(); // 這裡的 test 是什麼? 

        在瀏覽器執行時監控test的結果:


        最後一行程式碼變為:

var test = Test(); // 這裡的 test 是什麼?(new去掉)。

        在瀏覽器執行時監控test的結果:


如果在上面的程式碼變為:

function Test() {  
  this.name = 'Test';  
  return function() { return true; }  
} 
alert(new Test() == Test() );

        執行結果:


      以上結果會讓人很迷惑。兩個最後的結果明顯相同,但是為什麼真正比較的時候返回的是false呢。因為 Javascript  對於 Object 和 Function 的比較是基於引用的。

  為了更清晰的分辨在上述情形下兩者間的區別,請繼續看以下程式碼

function Test() {  
  this.name = 'Test';  
  return 'Test';  
}  
  
var fnT = Test();  
var newT = new Test();  

        在瀏覽器執行時監控fnT和newT的結果:


        這次終於有了明顯的區別。顯然,fnT是字串 Test,那 newT呢?呵呵,是不是被第一個樣例迷惑了?其實,此時 newT是一個 Test物件——有一個名為 name的屬性,其值為字串 Test

        通過上面兩段程式碼,我們可以得出一個猜測,如果函式返回值為常規意義上的值型別(NumberStringBoolean)時,new函式將會返回一個該函式的例項物件,而如果函式返回一個引用型別(ObjectArrayFunction),則new函式與直接呼叫函式產生的結果等同。通過在 Test函式中返回不同型別的值進行測試,可以證實這一點。  

        分清這一點,其實還是蠻重要的,至少在看一些面向物件的框架類庫程式碼時,會少一些疑惑。(再次感謝網友咲臣”讓我從思考中又一次收穫了很多,當然也感謝其他朋友對我的部落格給出意見和建議。).