document.write, onload и переменная область видимости
Я весь день боролся с 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 ответа
Я тестировал на 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)
Во-первых, я настоятельно рекомендую не использовать 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>
Я подозреваю, что onA1Ready() вызывается onLoad, который пишет другую функцию для вызова onLoad, которая никогда не вызывается, так как документ уже загружен.