2012-08-10 39 views
3

這是一個棘手的問題,讓我撓了腦袋幾天。用JavaScript清除窗口對象中的自定義變量

我正在研究一個項目,該項目涉及到一個十年的Web應用程序並將其作爲單頁應用程序重新處理。應用程序非常龐大 - 我們必須工作的時間非常緊密,因此必須制定一些捷徑。

然而,總體來說,我們對我們來到的距離印象深刻,因爲我們必須克服一些有趣的技術障礙。

一個涉及清除所有自定義窗口變量。由於我們正在動態地重新加載應用程序的不同頁面,因此我們需要清除所有自定義變量,以免發生衝突。我們所做的首先是加載應用程序的基本引導程序,並將窗口對象中的所有屬性保存在一個數組中。然後,在加載每個新頁面之前,我們循環瀏覽窗口屬性並清除所有不在我們保存的數組中的對象(將窗口狀態返回到加載頁面之前)。

現在,在我們測試過的所有瀏覽器中,除了IE7和IE8(這兩者都需要支持)以外,這樣的工作正常。問題似乎是全局變量似乎並不總是在窗口對象上註冊。

有沒有人對這個問題有所瞭解?任何想法如何解決這個IE7?

任何信息將不勝感激。

編輯: 在引導裝入我們這樣做:

for (i in window) { 
    this.globalVars[i] = 1; 
} 

然後當我們加載一個新的頁面(通過AJAX),我們這樣做:

for (i in window) { 
    if (!this.globalVars[i]){ 
     window[i] = undefined; 
    } 
} 

最終的解決方案:

最後,由於時間有限,最簡單的修復方法是簡單地將所有變量定義爲var x;到var x = null;

然而,我發現了另一種解決方案。這裏有一個小型圖書館,我用它作爲替代解決方案的起點:http://www.thomasfrank.se/global_namespace.html

這並不完美(可能需要進行一些調整以使其更穩定一些,例如在AJAX調用中添加try-catch塊例如,以便跨域腳本不會崩潰)。它的工作方式是對所有外部腳本文件和內部腳本進行分析,提取大量單詞,然後可以使用這些單詞清除窗口對象的屬性。

我們實際上經歷了一些非常奇怪的事情 - 這個腳本沒有正確地提取很多變量......事實證明,它使用document.scripts來獲取頁面上所有加載的腳本,以便能夠循環通過他們並解析它們。問題是jQuery不會以這種方式在頁面上加載外部頁面。它所做的只是將代碼從我知道的傳遞給exec。因此,沒有腳本標記實際上被添加到頁面中。

解決方法是解析原始AJAX響應並存儲對所有腳本標記的引用(以及我想提取內聯腳本),然後修改該庫以便能夠處理這些文件。這應該有效,但所有這些處理過程都因爲速度原因而太可怕 - 發現我們可以簡單地在所有變量定義上進行搜索&替換,並且大部分工作無需每個頁面加載的大量工作顯然我們應該採取哪條道路。

+0

爲「清除」自定義變量的任何示例代碼? – 2012-08-10 05:53:57

+0

窗口對象的哪些屬性在這裏似乎是問題?你確認他們在循環瀏覽窗口對象時顯示了嗎?我的第一個想法是,已知的問題循環使用'x in something',也許你遇到了這個問題。 – WTK 2012-08-10 13:20:36

+0

這些問題不是主要與循環數組相關的問題,而不是與對象相關的問題?無論如何,問題在於IE7似乎並沒有在窗口對象上添加所有全局變量作爲屬性,所以它不會像循環一樣出現。但是,如果您嘗試直接訪問它,則可以訪問它。 – NRaf 2012-08-11 03:09:57

回答

3

據我所知,如果你想這是一個「快速」的解決方案,確保所有全局變量的100%被重置,並且這與oldIE兼容,你基本上必須保存您修改的窗口/文檔屬性的初始值......以及爲特定頁面上的每個全局手寫空值。

如果你希望它是100%準確的,完全不用重構任何形式的......這就是我在未來所預見的。

貴公司聽起來像幾個我知道(我敢肯定,每個人都知道幾) -
「奇蹟可以在任何時間發生的沒有錢,如果我們告訴開發者,使他們發生」如果涉及到它,我會通過手工挑選並修復全局var問題(或者編寫一個解析器來查找頁面上的全局範圍變量 - 或者至少指向它們可能在的位置) 。 該框架的其餘部分可能會被黑客攻擊......儘管如此,如果可能的話,我還是希望能找到沙盒頁面(會讓整個狀態變得毫無意義,對於初學者來說,一旦沒有全局變量)。

但是......任一空的每一頁的全局手工,或修復它們,用手將它們應用或者作爲window[key](在絕對必要的),或作爲formerly_global_properties[key]或在完全不同的範圍內,封閉在一個功能。所有這些都是向後兼容的,並且都將會非常糟糕。

但是黑客攻擊這樣的解決辦法和黑客的全局弄成可行的,然後可以用/維持工作在以後的日子都將是大致相同的工作數量,對不對?

+0

這是我們經歷並實施的解決方案(定義爲空)。實際上,這只是數量有限的頁面,而且效果不佳。 – NRaf 2012-08-16 23:25:01

4

退房這個問題:JavaScript: List global variables in IE

在IE瀏覽器,它的全局變量是不可枚舉的,除非你明確地將它們定義爲window對象的屬性。

所以,如果你正在分配這樣的變量:

var number = 42; // not inside any function 

它不會顯示出來,當你通過迭代window。你必須定義所有的全局變量是這樣的:

window.number = 42; 

或者這樣:

this.number = 42; 
+0

xD,+1似乎我們在同一時間寫作:D – gaspyr 2012-08-12 22:47:20

+0

是的,我知道這一點。我所希望的是一種解決方案,無需更改應用程序中的每個全局變量聲明(這可能導致錯誤,難以測試並且非常耗時)。 – NRaf 2012-08-13 00:38:42

+0

@NRaf我認爲情況會如此。我想知道你是否可以重新加載所有的js ...我根本不是那個想法的粉絲,但它可能是解決問題的唯一方法。 – lbstr 2012-08-13 00:47:11

1

你檢查如果循環過程中不顯示這些屬性設置爲不可枚舉。因爲如果一個對象的屬性不是可枚舉的,那麼它在循環過程中不會「顯示」。你可以用下面的方法「propertyIsEnumerable」來檢查它。

例如:

var o = {x:1, y:2, z:3}; // Three enumerable own properties 
o.propertyIsEnumerable("toString") // => false: not enumerable 

作爲附帶說明:

據的ECMAScript 5 for/in循環一次爲每個 枚舉屬性運行循環體(自身或繼承)的指定對象,將該屬性的名稱分配給循環變量。對象繼承的內置方法不是 可枚舉,但是您的代碼添加到對象的屬性是可枚舉的(除非 您使它們不可枚舉)。

0

,如果你包裹在什麼封閉的舊腳本並保存/導出,你需要堅持的變量?

1

我會建議使用刪除,一個鮮爲人知的JS功能正常擺脫全局變量,例如

delete window.varname; 

OR

delete window["varname"]; 

設置爲未定義的變量是相當於(以全球範圍)

var varname; 

這可能不是你想要的。

+0

在ie8中不起作用。實際上拋出異常... – Ajax 2014-10-10 18:40:48

0
clone(obj) { 
     var _ = this, 
      copy; 
     if (null == obj || "object" != typeof obj) return obj; 
     if (obj instanceof Date) { 
      copy = new Date(); 
      copy.setTime(obj.getTime()); 
      return copy; 
     } 
     if (obj instanceof Array) { 
      copy = []; 
      for (var i = 0, len = obj.length; i < len; i++) { 
       copy[i] = _.clone(obj[i]); 
      } 
      return copy; 
     } 
     if (obj instanceof Object) { 
      copy = {}; 
      for (var attr in obj) { 
       if (obj.hasOwnProperty(attr)) copy[attr] = _.clone(true); 
      } 
      return copy; 
     } 
     throw new Error("Unable to copy obj"); 
    } 

    windowGarbageCollection(){ 
     var removeObjects = Object 
      .keys(window) 
      .map((currentValue) => { 
       if(!window.window_cache[currentValue]){ 
        if(currentValue != 'window_cache' && currentValue != '0'){ 
         window[currentValue] = false; 
        } 
       } 
      }); 
    } 

    // run this at the moment you want to grab the initial variables 
    // probably at the very beginning 
    window.window_cache = clone(window); 

首先創建初始window變量(你不需要整個窗口對象)的快照,並將其存儲在window.window_cache

然後每次你在你的應用程序切換頁面時,運行windowGarbageCollection(),這會比較window.window_cache當前的window,把事情以後添加到false

你會想在開始新的頁面呈現之前運行的垃圾收集,這樣,當它呈現的任何新變量將不會刪除。