0

我想js动态附加几个文件。每个文件都有一个函数定义,我想将其代码保存在对象的属性中。我使用纯 JavaScript 和script标签。但onload事件无法正常工作。如果我只包含一个文件,一切正常。但如果超过一个,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);

    };
};

正如我在一开始所说,如果我加载一个文件,一切都会正常工作。但是对于不止一个,onload工作两次,但仅适用于我的第二个文件 - 带有函数'two'定义。警报触发两次并显示'two'. 而且我只有'two'我的财产的功能'two',这是我通过参数传递的最后一个功能。并且文件被附加在 DOM 文件中。

我试图在循环<script>之外创建标签for/in,甚至创建了一个数组并将两个脚本中的每一个保存为该数组的单独元素,但它也无济于事 - 只有最后一个文件在onloadand 两次。

问题是什么?为什么它不适用于两个文件?有可能解决吗?

4

1 回答 1

1

很难判断何时不包含完整的代码,但很可能会遇到闭包问题。

您在 for 循环中定义了 onload 函数,这意味着它将绑定对“key”局部变量的引用。当“卸载”函数实际运行时,for 循环已经完成,“key”将是“two”,所以你会在两个警报中看到“two”。

这是同一问题的一个更简单的示例:

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

当你运行它时,你会得到两个警报,每个警报都显示“2”,这是循环退出后“x”的值。

要解决此问题,您需要调用一个函数,该函数在超时发生时返回您要调用的函数:

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 回答