3

これはトリッキーな問題で、数日間頭を悩ませてきました。

私は、10年前のWebアプリケーションを取得し、それを1ページのアプリケーションとして作り直すプロジェクトに取り組んでいます。アプリケーションは巨大です-私たちが作業しなければならない時間は非常にタイトなので、いくつかのショートカットを作成する必要がありました。

しかし、全体として、いくつかの興味深い技術的ハードルを克服しなければならなかったので、私は私たちがどれだけ遠くまで来たかに非常に感銘を受けました。

1つは、すべてのカスタムウィンドウ変数をクリアすることでした。アプリケーションのさまざまなページを動的に再読み込みするため、競合が発生しないように、すべてのカスタム変数をクリアする必要があります。まず、アプリケーションのベースブートストラップをロードし、ウィンドウオブジェクトのすべてのプロパティを配列に保存します。

次に、新しい各ページをロードする前に、ウィンドウのプロパティをループして、保存された配列にないすべてのオブジェクトをクリアします(ページがロードされる前のウィンドウの状態に戻ります)。

これで、IE7とIE8(どちらもサポートする必要があります)を除いて、テストしたすべてのブラウザーで正常に機能します。問題は、グローバル変数が常にウィンドウオブジェクトに登録されているとは限らないことです。

誰かがこの問題について何か洞察を持っていますか?このIE7に取り組む方法はありますか?

任意の情報をいただければ幸いです。

編集:ブートストラップのロード時にこれを行います:

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

そして、(AJAXを介して)新しいページをロードするとき、次のことを行います。

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

最終的解決:

結局、限られた時間で最も簡単な修正は、varxとして定義されたすべての変数を変更することでした。var x=nullへ;

しかし、私が見つけた別の解決策がありました。ここに、別のソリューションの開始点として使用した小さなライブラリがありました:http ://www.thomasfrank.se/global_namespace.html

完全ではありません(たとえば、クロスドメインスクリプトがクラッシュしないように、AJAX呼び出しの周りにtry-catchブロックを追加するなど、もう少し安定させるために微調整が必​​要になる場合があります)。それが機能する方法は、すべての外部スクリプトファイルと内部スクリプトが解析され、ウィンドウオブジェクトからプロパティをクリアするために使用できる大量の単語を抽出することです。

私たちは実際に非常に奇妙なことを経験しました-このスクリプトは多くの変数を適切に取得していませんでした...それはdocument.scriptsを使用して、ページにロードされたすべてのスクリプトをループして解析できるようにします彼ら。問題は、jQueryがその方法でページ上の外部ページをロードしないことです。それが行うことは、私が知っていることからexecにコードを渡すことです。そのため、スクリプトタグは実際にはページに追加されません。

これに対する修正は、生のAJAX応答を解析し、すべてのスクリプトタグへの参照を保存し(そして、おそらくインラインスクリプトを抽出します)、これらのファイルを処理できるようにライブラリを変更することです。これは機能するはずですが、速度の理由から、この処理はすべて怖すぎました。すべての変数定義を検索して置換するだけで、ページの読み込みごとに大量の作業を必要とせずにほとんどの作業を実行できることがわかりました。どの道をたどるべきかは明らかです。

4

6 に答える 6

4

この質問をチェックしてください:JavaScript:IEのグローバル変数を一覧表示する

IEでは、グローバル変数をウィンドウオブジェクトのプロパティとして明示的に定義しない限り、グローバル変数を列挙することはできません。

したがって、次のような変数を割り当てる場合は、次のようになります。

var number = 42; // not inside any function

を繰り返し処理しているときは表示されませんwindow。すべてのグローバルを次のように定義する必要があります。

window.number = 42; 

またはこのように:

this.number = 42; 
于 2012-08-12T22:46:08.073 に答える
3

私の知る限り、これを「迅速に」解決して、すべてのグローバル変数を100%リセットし、oldIEと互換性があるようにする場合は、基本的にウィンドウの初期値を保存する必要があります。変更する/documentプロパティ......特定のページの各グローバルのnull値を手書きします。

100%正確で、古いIEを使用して完全にBCにしたい場合は、リファクタリングを一切行わずに......それが将来の見通しです。

あなたの会社は私が知っている少数のように聞こえます(誰もがいくつか知っていると確信しています)-
「開発者に奇跡を起こさせるように指示すれば、奇跡はすぐにお金なしで起こる可能性があります。」

結局のところ、私はグローバル変数の問題を手作業で選択して修正したでしょう(または、ページ上でグローバルスコープの変数を見つけるためのパーサーを作成しました-または少なくともそれらが存在する可能性のある場所を指し示します)。フレームワークの残りの部分は一緒にハッキングされる可能性があります......ただし、可能であれば、ページをサンドボックス化することを望んでいます(グローバルが存在しなくなった場合、最初に、州全体が無意味になります) 。

しかし、ええ... ...各ページのグローバルを手動でnullにするか、手動で修正して、window[key](絶対に必要な場合)として、またはformerly_global_properties[key]関数で囲まれたまったく異なるスコープとして、またはまったく異なるスコープで適用します。すべてが下位互換性があり、すべてが計り知れないほどひどいものになります。

しかし、このような回避策をハッキングすることと、グローバルをハッキングして実行可能なものにハッキングし、それを後日処理/保守できるようにすることは、どちらもほぼ同じ量の作業になりますよね?

于 2012-08-16T00:56:42.333 に答える
3

グローバル変数を適切に取り除くために、あまり知られていないjs機能であるdeleteを使用することをお勧めします。

delete window.varname;

また

delete window["varname"];

変数をundefinedに設定することは、(グローバルスコープで)と同等です。

var varname;

それはあなたが望むものではないかもしれません。

于 2012-08-16T11:47:08.360 に答える
1

ループ中に表示されないプロパティが列挙不可として構成されているかどうかを確認しましたか。オブジェクトのプロパティが列挙可能でない場合、ループ中に「表示」されないためです。次のメソッド「propertyIsEnumerable」で確認できます。

例 :

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

補足として:

ECMAScript 5によると、for / inループは、指定されたオブジェクトの列挙可能なプロパティ(所有または継承)ごとにループの本体を1回実行し、プロパティの名前をループ変数に割り当てます。オブジェクトが継承する組み込みメソッドは列挙できませんが、コードがオブジェクトに追加するプロパティは列挙可能です(オブジェクトを無数にしない限り)。

于 2012-08-12T22:46:42.153 に答える
0

古いスクリプトをクロージャでラップし、永続化する必要のある変数を保存/エクスポートした場合はどうなりますか?

于 2012-08-16T01:03:39.583 に答える
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_cachewindowfalse

新しいページがレンダリングされる前に最初にガベージコレクションを実行して、レンダリング時に新しい変数が削除されないようにする必要があります。

于 2017-07-17T15:59:07.117 に答える