0

js複数のファイルを動的に追加したい。各ファイルには関数定義があり、そのコードをオブジェクトのプロパティに保存したいと思います。プレーンなJavaScriptとscriptタグを使用しています。しかし、onloadイベントは正しく機能しません。1つのファイルだけを含めると、すべてが正常に機能します。しかし、複数ある場合onloadは、故障しています。これが私のコードです、それはオブジェクトのメソッドです:

// My files I want to include:
one.js
   function one() { alert('one') };

two.js
   function two() { alert('two') };

// My code in the object 
var one = null;
var two = null;   // In these properties I want to save my functions

function inc(files) {   // 'files' is the object {one: 'one', two: 'two'}
                        'one' and 'two' are names of function in my files
    for (key in files) {

       var script = document.createElement('script');
       script.setAttribute('type', 'text/javascript');

       var fullPath = '/path/to/file/' + files[key] + '.js';   // /path/to/file/one.js, /path/to/file/two.js,
       script.setAttribute('src', fullPath);


       // And here's my eventhandler. After the script is loaded,
       // names of my functions are in global scope. So, the task is:
       // to take them and save in properties using setter.
       script.onload = function() {

           setProps(window[files[key]]);   // setProp(window.one / window.two);
           window[files[key]] = null;      // remove them from global scope

           alert(one/two);   // to check if I have functions saved in properties
       }

       document.getElementsByTagName('head').item(0).appendChild(script);

    };
};

最初に言ったように、1つのファイルをロードすればすべてが正常に機能します。しかし、複数の場合はonload2回動作しますが、関数定義を使用した2番目のファイルに対してのみ機能し'two'ます。Alertは2回発生し、のコードを表示します'two''two'そして、私は自分のプロパティの関数しか持っていません'two'。これは、パラメータを使用して最後に渡した関数です。そして、ファイルはDOMだけのファイルに追加されます。

<script>ループの外側でタグを作成しようとしfor/inました。配列を作成し、2つのスクリプトのそれぞれをその配列の個別の要素として保存しましたが、どちらも役に立ちません。最後のファイルonloadだけがと2回にあります。

何が問題ですか?2つのファイルで機能しないのはなぜですか?それを解決することは可能ですか?

4

1 に答える 1

1

完全なコードが含まれていない場合はわかりにくいですが、クロージャの問題が発生している可能性があります。

forループ内にonload関数が定義されています。これは、「キー」ローカル変数への参照をバインドすることを意味します。「unload」関数が実際に実行されるまでに、forループが完了し、「key」が「two」になるため、両方のアラートに「two」が表示されます。

同じ問題のより簡単な例を次に示します。

for (x=0; x< 2; x++) {
   setTimeout(function() {
       alert(x);
   }, 100);
}

これを実行すると、2つのアラートが表示されます。各アラートには、ループが終了した後の「x」の値である「2」が表示されます。

これを修正するには、タイムアウトが発生したときに呼び出したい関数を返す関数を呼び出す必要があります。

function create_alerter(z) {
    return function() {
        alert("fixed: " + z);
    }
}

for (x = 0; x < 2; x++) {
    setTimeout(create_alerter(x), 100);
}

このための個別の関数が必要ない場合は、関数を返す関数を定義して、インラインで呼び出すことができます。

for (x = 0; x < 2; x++) {
    setTimeout(function(z) {
       return function() {
          alert(z);
       }
    }(x), 100);
}
于 2012-11-06T00:04:37.703 に答える