2013-10-15 25 views
3
<script type="text/javascript"> 
function BigComputer(answer) { 
    this.the_answer = answer; 
    this.ask_question = function() { 
    alert(this.the_answer); 
    } 
} 

function addhandler() { 
    var deep_thought = new BigComputer(42), 
    the_button = document.getElementById('thebutton'); 

    the_button.onclick = deep_thought.ask_question; 
} 

window.onload = addhandler; 
</script> 

爲什麼此腳本返回undefined而不是42? 這是我的理解:
1)在網頁加載時,我們運行'addhandler'方法。
2)在這個方法中,我們爲deep_thought變量創建BipComputer的實例。此外,我們建立了42處答案(BipComputer類中的公共變量)
3)然後,我們設置了按鈕參考(HTML文件中)
4)點擊按鈕活性和來這裏的魔法:
在我意見是要打印出42號,因爲我們在第2步爲此做了設置,但是nah變量是「Undefined」?

Javascript - Scopes

另一個問題,運行沒有()(沒有參數傳遞時)和()方法之間的區別是什麼。 [像addhandler方法]。

也許這個問題很簡單,但我曾經用java和php編程,現在在面向JavaScript的編程思維方式對我來說很奇怪。函數看起來像類,類看起來像函數,沒有真正的構造函數和東西。
但沒關係,讓我們回到問題:)
我真的很感激任何幫助。




@Edit

感謝@lbstr我發現有用的鏈接,大家誰在問同樣的問題,像我一樣。 http://web.archive.org/web/20080209105120/http://blog.morrisjohns.com/javascript_closures_for_dummies

+2

addhandler在該示例中沒有被顯式調用。它被傳遞爲瀏覽器在適當的時候調用的'window.onload'的引用。只有當你把它作爲構造函數調用時,你纔可以不用'()'來執行一個函數。 – zzzzBov

+0

@ zzzzBov-該函數被添加爲一個按鈕的點擊監聽器,所以它被按鈕的點擊處理程序調用。 – RobG

+0

@RobG,讓我改述一下,只有當你把它作爲一個構造函數(即'new Foo')調用時,你纔可以明確地執行一個不帶'()'的函數。任何其他情況都需要調用瀏覽器函數或行爲來爲您調用函數。 – zzzzBov

回答

6

當單擊處理程序被激發,this是按鈕。這是你想要做的:

function BigComputer(answer) { 
    this.the_answer = answer; 
    var self = this; 
    this.ask_question = function() { 
     alert(self.the_answer); 
    }; 
} 

這一切都由封閉的美妙成爲可能。許多js粉絲都認爲這是該語言最好的部分。 Read all about 'em

區分範圍與this很重要。雖然變量的作用域不同,但this在給定作用域鏈中不一定相同。一個簡單的例子是,我可以調用我想,我想的this任何價值的任何功能的事實:

someFunc.call(someThis); // call someFunc, using someThis for this 

事件處理程序,this通常是在該事件起源的元素。這很好,因爲你可能在頁面上有幾個按鈕,你想對被點擊的按鈕做點什麼。

+0

所以我需要使用「var self = this」,每當我使用DOM元素時?它不應該作爲它創建的對象的範圍工作嗎? – Dariss

+0

@Dariss偉大的問題 - 見我上面的編輯,這將有望回答它。 – lbstr

+0

@ Dariss - 一個函數的* this *由函數的調用方式(或[* bind *])設定(http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.4.5 ))。所以如果你在通話中沒有設置正確的* this *,你以後就不能修復它。在閉包中保留對實例的引用會使其再次可用,儘管這不是一種特別有效的方法。最好制定出另一個計劃。 – RobG

0

當您將ask_question()指定爲從按鈕單擊執行時,「this」將是該按鈕的上下文,而不是基於構造函數的deep_thought變量的上下文。如果您從this.the_answer中刪除「this」並將其設置爲var,則您將獲得42的警報。

4

的問題是,您分配

the_button.onclick = deep_thought.ask_question; 

後,單擊該按鈕時,分配給onclick屬性的函數被調用,this綁定按鈕。通過使用bind創建執行ask_question與所需this一個新的功能,通過重寫的功能(如在the answer by lbstr

    • :可以解決(至少)三個方面的問題:

      the_button.onclick = deep_thought.ask_question.bind(deep_thought); 
      

      請注意bind是JS 1.8.5的新功能;上面的鏈接爲舊的JS引擎提供了一個墊片。

    • 通過寫關閉,以獲得正確的thisask_question

      the_button.onclick = function() { deep_thought.ask_question(); }; 
      

      編輯:由於RobG在評論中指出,該代碼創建在某些瀏覽器(MSIE的特別是許多版本)內存泄漏。一個解決將是消除變量​​完全:

      document.getElementById('thebutton').onclick = function() { 
          deep_thought.ask_question(); 
      }; 
      

      其他方法見this tutorial

  • +0

    +1包括解決這個問題的可能性。 – jfriend00

    +0

    用於提及綁定的+1 – lbstr

    +1

    最後一個建議確實創建了一個閉包,但這不是它工作的原因。它只是在通話中將* this *設置爲正確的值。這些關閉是未使用的(並且因爲在這種情況下在一些瀏覽器中可能導致內存問題而不受歡迎)。下一行應該是'the_button = null'來移除由閉包引起的最有問題的循環引用。 – RobG

    相關問題