2

在本教程中提到的here,由模塊提供的命名空間是:命名空間問題

goog.provide('tutorial.notepad.Note');

但我很奇怪,爲什麼不是這個:

goog.provide('tutorial.notepad');

由於,根據下面提到的規則:

tutorial = tutorial || {}; 
tutorial.notepad = tutorial.notepad || {}; 
tutorial.notepad.Note = tutorial.notepad.Note || {}; 

如果我們只是提供:

goog.provide('tutorial.notepad');那麼,我們就已經有了:

tutorial = tutorial || {}; 
tutorial.notepad = tutorial.notepad || {}; 

,這是我們本可以添加的屬性Note

tutorial.notepad.Note = function() {}; 

因此,我的問題是:

爲什麼不只是聲明goog.provide('tutorial.notepad')然後用它來包含頂級Classes,而不是其推薦使用goog.provide('tutorial.notepad.Note')每個Class這對我來說是多餘的。

回答

2

擁有goog.provide('tutorial.notepad');在該名稱空間的「依賴關係樹」中創建條目,但它不會爲類tutorial.notepad.Note創建條目。如果您在示例代碼中手動創建tutorial.notepad.Note,那麼您不會激活閉包編譯器機制以將類tutorial.notepad.Note包含到閉包編譯器使用的名稱空間依賴關係樹中。

原因是閉包編譯器使用goog.provide來設置依賴關係樹,用於確定要加載哪些命名空間以及以何種順序。

通過不使用goog.provide,而是使用您顯示的代碼模擬其效果,編譯器不會了解類Note以及它如何適合名稱空間和類樹及其依賴項。

運行基於閉包編譯器的代碼有兩種方法:編譯和未編譯。每一種構建和使用命名空間的依賴不同的樹:

  • 未編譯一個關於關閉編譯偉大的事情是,你可以運行所有的代碼未編譯。該過程中的一個必要步驟是使用depswriter.py,這是一個可讀取所有源文件(查找goog.providegoog.require調用)並生成文件deps.js的Python程序。 deps.js文件是命名空間依賴關係樹的實例。這裏是一個樣本線(333)從我的項目的deps.js文件:

    goog.addDependency('../../../src/lab/app/ViewPanner.js', 
        ['myphysicslab.lab.app.ViewPanner'], ['myphysicslab.lab.util.DoubleRect', 
        'myphysicslab.lab.util.UtilityCore', 'myphysicslab.lab.util.Vector', 
        'myphysicslab.lab.view.CoordMap', 'myphysicslab.lab.view.LabView'], false); 
    

當我在未編譯狀態下運行我的代碼,有可能運行一個deps.js腳本<script>標籤。這樣做會導致名稱空間依賴關係樹的內存版本被創建,在運行時由goog.require訪問,以加載該特定類所需的任何其他文件。

  • 編譯編譯器(Java程序)不會多如上作爲編譯過程的一部分中描述的相同的事情。所不同的是,命名空間依賴關係的樹只在編譯期間用於確定如何定義類的順序,找出需要什麼等等。當編譯完成時,名稱空間依賴關係的樹被放棄。

參考文獻:

https://github.com/google/closure-compiler/wiki/Managing-Dependencies

https://github.com/google/closure-compiler/wiki/Debugging-Uncompiled-Source-Code


響應您的評論:

爲什麼不申報goog.provide('tutorial.notepad'),然後用它來包含頂級Classes,而不是它的推薦使用goog.provide('tutorial.notepad.Note')每個Class這對我來說是多餘的。

我認爲這會導致關於閉包編譯器目標和設計的問題。正如@Technetium指出的那樣,使用閉包編譯器「非常冗長」 - 它需要使用註釋來標註JavaScript代碼,以告訴每個方法(函數)的輸入和輸出類型以及對象的每個屬性的類型(類)。我認爲按照你的建議要求編譯器「理解」你的代碼,並猜測你認爲什麼是類,以及你認爲是構造函數和什麼是構造函數。方法或該類的其他屬性。這會比閉包編譯器設計者所遇到的問題困難得多 - 特別是因爲JavaScript是一種「鬆散」語言,可以讓你幾乎可以做任何你能想到的事情。

實際上我發現goog.provide一點也不麻煩。我通常只爲每個文件定義一個類。我發現更多的麻煩是所有的goog.require陳述。我通常可以在一個文件中有20或30個這樣的文件,這個文件列表經常在類似的類中重複。我的代碼中有3870次出現goog.require

即使這將是美好的,但什麼使情況變得更糟的是,關閉編譯器有一個goog.scope機制,它可以讓你使用更短的名字,像我就可以說Vector而不是new myphysicslab.lab.util.Vector。這是非常好的,但問題是,每一類你已經goog.requireð你就必須使goog.scope在短期內變量,這樣一行:

var Vector = myphysicslab.lab.util.Vector; 

不管怎樣,我的觀點是:是的,封閉編譯器比原始JavaScript需要更多的代碼。但goog.provide是這方面問題中最少的。

一兩件事:用戶@Technetium指出

的真正原因使用它是通過javascript的對JavaScript的關閉編譯器是去除死皮/無用的代碼,同時最小化和模糊處理來運行你的谷歌代碼閉幕你使用的作品。

雖然這是一個非常有用的功能,就有可能使用封閉編譯另一個非常重要的原因是:類型檢查。如果您花時間將註釋添加到您的函數中,那麼編譯器將通過捕獲錯誤來「回過頭來」。這對任何項目都有很大的幫助,但是如果有多個開發人員在項目中工作,並且這是Google開發閉包編譯器的主要原因之一,這將變得非常重要。在這裏打球

+0

誰說我不使用'goog.provide'?請仔細閱讀問題。 – CodeYogi

+0

我在開頭添加了一段。也許我還沒有理解你的問題? – owler

+0

更新我的問題,希望現在清楚。 – CodeYogi

1

有兩件事情:

  1. 只能喚起goog.provide()每個命名空間一次。

您目前可能有你在一個文件中定義的「階級」,說Note.js,與goog.provide('tutorial.notepad');現在。但是,如果添加另一個文件,如Tab.js,其中包含「類」tutorial.notepad.Tab,則當Tab.js也稱爲goog.provide('tutorial.nodepad')時,您將碰到this error

  • 調用goog.provide('tutorial.notepad')沒有告訴關閉編譯器對「類」 tutorial.notepad.Note
  • 谷歌封閉碼是在它的原始庫形式非常冗長。使用它的真正原因是通過javascript-to-javascript Closure編譯器運行您的Google Closure代碼,該代碼可以刪除死/未使用的代碼,同時最大限度地減少和混淆做的做的作品的使用。雖然您的示例在調試模式下工作,因爲它沒有利用Closure Compiler,所以一旦Closure Compiler運行並嘗試構建依賴關係映射,當嘗試通過goog.requires('tutorial.notepad.Note')引用它時,它將無法找到tutorial.notepad.Note類。如果你想了解更多關於這個依賴關係圖的工作原理,owler的答案是一個非常好的開始。

    另外,請注意,我在引號中使用了「class」,並且非常有意。雖然Google Closure通過其@constructor註釋以及許多方式通過goog.provide/goog.require語法爲package/import提供了面向對象編程的外觀和風格,但在一天結束時它仍然是JavaScript。