document.write, onload и переменная область видимости - PullRequest
2 голосов
/ 13 января 2012

Я весь день боролся с document.write и функцией onLoad.

Если вы считаете код JS таким, как этот =>

window.i = 0;
console.log(i + " //should be 0");

document.write("<scr"+"ipt onLoad='onA1Ready()' src='a1.js'><\/sc"+"ript>");

function onA1Ready(){
    document.write("<scr"+"ipt onLoad='onA2Ready()' src='a2.js'><\/sc"+"ript>");
}

function onA2Ready(){
    console.log(i + " //should be 2");
} 

и a1.js вот так =>

i++;
console.log(i + " //should be 1");

и a2.js очень похожи =>

i++;
console.log(i + " //should be 2");   

Я ожидаю, что последний вывод на консоль будет равен 2, но вместо этого вот что я получаю из консоли =>

0 //should be 0     test.js (line 2)
1 //should be 1     a1.js (line 2)
i is not defined    ERROR i++; a2.js (line 1)
onA2Ready is not defined

Я думаю, что эта проблема связана с областью действия, но я не могу понять, как.

Было бы замечательно, если бы кто-нибудь из вас имел представление о том, что здесь происходит.

Ответы [ 3 ]

1 голос
/ 13 января 2012

Я тестировал на Chrome 16, и все работало как ожидалось. Однако в последнем FF я получил ошибку, которую вы описали.

Мой совет - прекратить использовать зло document.write() для динамической загрузки скриптов. Вместо этого используйте методы DOM. Я написал небольшую функцию myLoader(), которая может помочь вам

window.i = 0;
console.log(i + " //should be 0");

var myLoader = function(filename, fun) {
  var head   = document.getElementsByTagName('head')[0],
      script = document.createElement('script');
  script.type= 'text/javascript';
  script.src = filename;
  if(typeof fun === 'function'){ script.onload = fun; }
  head.appendChild(script);
};


myLoader('a1.js', function(){
  myLoader('a2.js', function() {
    console.log(i + " //should be 2");
  });
});

Попробуйте.

На выходе я получаю

0 //should be 0         a0.js (line 2)
1 //should be 1         a1.js (line 2)
2 //should be 2         a2.js (line 2)
2 //should be 2         a0.js (line 17)
1 голос
/ 13 января 2012

Во-первых, я настоятельно рекомендую не использовать document.write.Это грязно и не нужно.

Добавление тега сценария гораздо лучше обрабатывается следующим образом:

var addScriptWithOnLoad = function(src, fn) {
    var s = document.createElement('script');
    s.setAttribute('type', 'text/javascript');
    s.setAttribute('src', src);
    s.onload = fn;
    document.head.appendChild(s);
};

Далее вам не следует использовать глобальную область видимости, так как вы полагаетесьбраузер играет хорошо, что никогда не является безопасной ставкой.Вы должны скорее передавать данные между функциями.Это, однако, немного выходит за рамки этого ответа.

следующий тег сценария, помещенный в заголовок веб-страницы , дает ожидаемый результат

<script type="text/javascript">
    window.i = 0;
    var addJS = function(src, fn) {
        var s = document.createElement('script');
        s.setAttribute('src', src);
        s.setAttribute('type', 'text/javascript');
        s.onload = fn;
        document.head.appendChild(s);
    };

    console.log(i + " //should be 0");

    var fn1 = function() {
        console.log();
        addJS('a2.js', fn2);
    };

    var fn2 = function() {
        console.log(i + " //should be 2");
    };

    addJS('a1.js', fn1);
</script>
0 голосов
/ 13 января 2012

Я подозреваю, что onA1Ready () вызывается onLoad, который записывает другую функцию для вызова onLoad, которая никогда не вызывается, поскольку документ уже загружен.

...