Ранее мы рассмотрели принцип работы JavaScript на основе механизма синтаксического анализа движка JavaScript. Теперь мы воспользуемся более ярким примером, чтобы проиллюстрировать порядок выполнения кода JavaScript на странице. Если рабочий механизм движка JavaScript относительно глубок, поскольку он принадлежит базовому поведению, то порядок выполнения кода JavaScript более нагляден, потому что мы можем интуитивно чувствовать этот порядок выполнения. Конечно, порядок выполнения кода JavaScript. сложнее, поэтому необходимо также профилировать язык JavaScript, прежде чем углубляться в него.
1.1 Выполнение кода JavaScript в порядке потока HTML-документа
Прежде всего, читатели должны знать, что процесс парсинга HTML-документов в браузере выглядит следующим образом: браузер постепенно анализирует структуру и информацию страницы сверху вниз в соответствии с потоком документов. Код JavaScript в виде встроенного сценария также следует считать компонентом HTML-документа, поэтому порядок выполнения кода JavaScript во время загрузки также определяется на основе порядка появления тега сценария <script>. Например, просмотрите страницу документации ниже, и вы увидите, что код анализируется шаг за шагом сверху вниз.
Скопируйте код кода следующим образом:
<скрипт>
alert("Лучший скрипт");
</скрипт>
<html><head>
<скрипт>
alert("головной сценарий");
</скрипт>
<title></title>
</голова>
<тело>
<скрипт>
alert("Скрипт страницы");
</скрипт>
</body></html>
<скрипт>
alert("нижний скрипт");
</скрипт>
Если внешний файл сценария JavaScript импортируется через атрибут src тега сценария <script>, то он также будет выполняться в том порядке, в котором появляются его операторы, и процесс выполнения является частью загрузки документа. Выполнение не будет отложено, поскольку это внешний файл JavaScript. Например, переместите сценарии в областях заголовка и тела документа выше во внешние файлы JavaScript, а затем импортируйте их с помощью атрибута src. Продолжая предпросмотр страницы документа, вы увидите тот же порядок выполнения.
Скопируйте код кода следующим образом:
<скрипт>
alert("Лучший скрипт");
</скрипт>
<html>
<голова>
<script src="//www.VeVB.COm/head.js"></script>
<title></title>
</голова>
<тело>
<script src="//www.VeVB.COm/body.js"></script>
</тело>
</html>
<скрипт>
alert("нижний скрипт");
</скрипт>
1.2 Связь между предварительной компиляцией и порядком выполнения
В Javascript функция — это первый тип Javascript. Когда мы пишем функцию, мы на самом деле просто создаем объект типа function.
Точно так же, как мы можем записать это в такой форме:
Скопируйте код кода следующим образом:
функцияHello()
{
Оповещение("Привет");
}
Привет();
варHello = функция()
{
Оповещение("Привет");
}
Привет();
На самом деле они все одинаковы. Но когда мы изменим функции, мы обнаружим очень странные проблемы.
Скопируйте код кода следующим образом:
<scripttype="text/javascript">
функцияHello() {
Оповещение("Привет");
}
Привет();
функцияHello() {
alert("Привет, мир");
}
Привет();
</скрипт>
Результат мы увидим следующим образом: Hello World выводится два раза подряд.
Вместо того «Привет и привет, мир», который мы себе представляли.
Это связано с тем, что Javascript не полностью интерпретируется и выполняется по порядку. Вместо этого Javascript «предварительно компилируется» перед интерпретацией. Во время процесса предварительной компиляции сначала будут выполняться определенные функции и будут созданы все переменные var, значение по умолчанию не определено для улучшения. эффективность выполнения программы.
Другими словами, приведенный выше фрагмент кода фактически предварительно скомпилирован движком JS в такую форму:
Скопируйте код кода следующим образом:
<scripttype="text/javascript">
varHello = функция() {
Оповещение("Привет");
}
Привет = функция() {
alert("Привет, мир");
}
Привет();
Привет();
</скрипт>
Из приведенного выше кода мы ясно видим, что функции также являются данными и переменными. Мы также можем присваивать (переназначать) значения «функциям».
Конечно, чтобы предотвратить такую ситуацию, мы также можем сделать следующее:
Скопируйте код кода следующим образом:
<scripttype="text/javascript">
функцияHello() {
Оповещение("Привет");
}
Привет();
</скрипт>
<scripttype="text/javascript">
функцияHello() {
alert("Привет, мир");
}
Привет();
</скрипт>
Таким образом, программа разделена на два раздела, и движок JS не объединяет их.
Когда движок JavaScript анализирует сценарий, он обрабатывает все объявленные переменные и функции во время предварительной компиляции.
Сделайте следующее:
1. Перед выполнением будет выполнена операция, аналогичная «прекомпиляции»: сначала будет создан активный объект в текущей среде выполнения, и те переменные, которые объявлены с помощью var, будут установлены как атрибуты активного объекта, но в это время , назначение этих переменных будет неопределенным, и те функции, которые определены с помощью функции, также добавляются как свойства активного объекта, и их значения в точности соответствуют определению функции.
2. На этапе интерпретации и выполнения, когда переменную необходимо проанализировать, сначала она будет искаться в активном объекте текущей среды выполнения. Если она не найдена и у владельца среды выполнения есть атрибут прототипа, она должна быть найдена. будет искаться в цепочке прототипов, в противном случае поиск будет осуществляться в соответствии с цепочкой областей. При обнаружении такого оператора, как var a = ..., соответствующей переменной будет присвоено значение (примечание: присвоение переменной завершается на этапе интерпретации и выполнения. Если переменная используется до этого, ее значение будет равно undefined). Таким образом, просто окажется, что сообщение об ошибке не будет получено, когда интерпретатор JavaScript выполнит следующий сценарий:
Скопируйте код кода следующим образом:
предупреждение(а); // возвращаемое значение неопределенное
вар а =1;
предупреждение(а); // возвращаем значение 1
Поскольку объявления переменных обрабатываются во время прекомпиляции, они видны всему коду во время выполнения. Однако вы также увидите, что при выполнении приведенного выше кода запрашиваемое значение неопределенно, а не 1. Это связано с тем, что процесс инициализации переменных происходит во время выполнения, а не перед компиляцией. Во время выполнения интерпретатор JavaScript анализирует код по порядку. Если переменной не присвоено значение в предыдущей строке кода, интерпретатор JavaScript будет использовать значение по умолчанию, неопределенное. Поскольку переменной a присваивается значение во второй строке, третья строка кода подскажет, что значение переменной a равно 1, а не неопределенному.
Аналогично, в следующем примере разрешен вызов функции до того, как функция будет объявлена и ее можно будет правильно проанализировать, поэтому возвращаемое значение равно 1.
Скопируйте код кода следующим образом:
f(); // Вызов функции, возвращаемое значение 1
функция е(){
предупреждение(1);
}
Однако если функция определена следующим образом, интерпретатор JavaScript выдаст синтаксическую ошибку.
Скопируйте код кода следующим образом:
f(); // Вызов функции и возврат синтаксической ошибки
вар f = функция(){
предупреждение(1);
}
Это связано с тем, что функция, определенная в приведенном выше примере, присваивается только переменной f как значение. Таким образом, в период предварительной компиляции интерпретатор JavaScript может обрабатывать только объявление переменной f, а значение переменной f — только. нажать во время выполнения. Если присваивания выполняются последовательно, естественным образом возникнет синтаксическая ошибка, указывающая, что объект f не может быть найден.
Пока, несколько примеров:
Скопируйте код кода следующим образом:
<тип сценария="текст/javascript">
/*Во время процесса предварительной компиляции func — это атрибут активного объекта в среде окна, а значение — это функция, охватывающая неопределенное значение*/
alert(func); //функция func(){alert("привет!")}
var func = "это переменная"
функция функция(){
предупреждение("Привет!")
}
/*Во время выполнения была обнаружена переменная var, которой было присвоено значение «это переменная»*/
предупреждение(функ); //это переменная
</скрипт>
Скопируйте код кода следующим образом:
<тип сценария="текст/javascript">
var name = "фэн" функция func();
{
/*Сначала присвойте имя неопределенному в среде func, а затем во время выполнения найдите атрибут имени активного объекта в среде func. На данный момент значение предварительно скомпилировано в неопределенное, поэтому выходные данные не определены. Фэн */
alert(name); //неопределенное имя var = "JSF";
оповещение(имя); //JSF
}
функция();
оповещение (имя);
//фэн
</скрипт>
Хотя объявления переменных и функций могут находиться в любом месте документа, рекомендуется объявлять глобальные переменные и функции перед всем кодом JavaScript, а также инициализировать и присваивать переменные. Внутри функции сначала объявляются переменные, а затем на них ссылаются.
1.3 Выполнение кода JavaScript блоками
Так называемые блоки кода представляют собой сегменты кода, разделенные тегами <script>. Например, два тега <script> ниже представляют два блока кода JavaScript.
Скопируйте код кода следующим образом:
<скрипт>
// блок кода JavaScript 1
вар а =1;
</скрипт>
<скрипт>
// блок кода JavaScript 2
функция е(){
предупреждение(1);
}
</скрипт>
Когда интерпретатор JavaScript выполняет сценарий, он выполняет его блоками. С точки зрения непрофессионала, если браузер встречает тег <script> при анализе потока HTML-документов, интерпретатор JavaScript будет ждать загрузки блока кода, сначала предварительно скомпилировать блок кода, а затем выполнить его. После выполнения браузер продолжает анализировать поток HTML-документов ниже, а интерпретатор JavaScript готов обработать следующий блок кода.
Поскольку JavaScript выполняется блоками, если вы вызываете переменную или функцию, объявленную в последующем блоке блока JavaScript, будет выдана синтаксическая ошибка. Например, когда интерпретатор JavaScript выполняет следующий код, он выдает синтаксическую ошибку, показывая, что переменная a не определена и объект f не может быть найден.
Скопируйте код кода следующим образом:
<скрипт>
// блок кода JavaScript 1
предупреждение(а);
е();
</скрипт>
<скрипт>
// блок кода JavaScript 2
вар а =1;
функция е(){
предупреждение(1);
}
</скрипт>
Хотя JavaScript выполняется блоками, разные блоки принадлежат одной глобальной области, а это означает, что переменные и функции между блоками могут использоваться совместно.
1.4. Используйте механизм событий для изменения порядка выполнения JavaScript.
Поскольку JavaScript обрабатывает код частями и следует порядку анализа потока HTML-документов, в приведенном выше примере вы увидите такие синтаксические ошибки. Но когда поток документов загружен, такая ошибка не возникнет при повторном обращении к нему. Например, если код, который обращается к переменным и функциям во втором блоке кода, поместить в функцию события инициализации страницы, синтаксических ошибок не будет.
Скопируйте код кода следующим образом:
<скрипт>
// блок кода JavaScript 1
window.onload = function(){ // Функция обработки событий инициализации страницы
предупреждение(а);
е();
}
</скрипт>
<скрипт>
// блок кода JavaScript 2
вар а =1;
функция е(){
предупреждение(1);
}
</скрипт>
По соображениям безопасности мы обычно разрешаем выполнение кода JavaScript только после инициализации страницы. Это позволяет избежать влияния скорости сети на выполнение JavaScript, а также избежать ограничений на выполнение JavaScript, вызванных потоком HTML-документов.
Уведомление
Если на странице имеется несколько обработчиков событий windows.onload, действителен только последний. Чтобы решить эту проблему, вы можете поместить все сценарии или вызывающие функции в один и тот же обработчик событий onload, например:
Скопируйте код кода следующим образом:
window.onload = функция(){
f1();
f2();
f3();
}
И таким образом порядок выполнения функций можно изменить, просто подкорректировав порядок вызова функций в обработчике события onload.
Помимо событий инициализации страницы, мы также можем изменить порядок выполнения кода JavaScript с помощью различных интерактивных событий, таких как события мыши, события клавиатуры, триггеры часов и т. д. Подробное объяснение можно найти в главе 14.
1.5 Порядок выполнения выходных сценариев JavaScript
При разработке JavaScript метод write() объекта документа часто используется для вывода сценариев JavaScript. Так как же выполняются эти сценарии динамического вывода? Например:
Скопируйте код кода следующим образом:
document.write('<script type="text/javascript">');
document.write('f();');
document.write('функция f(){');
document.write('alert(1);');
document.write('}');
document.write('</script>');
Запустив приведенный выше код, мы обнаружим, что: метод document.write() сначала записывает выходную строку скрипта в то место документа, где находится скрипт. После анализа содержимого документа, в котором находится document.write(), выполняется метод. Браузер продолжает анализировать содержимое вывода document.write(), а затем анализировать последующие HTML-документы по порядку. Другими словами, строка кода, выводимая сценарием JavaScript, будет выполнена сразу после вывода.
Обратите внимание, что вывод строки сценария JavaScript с использованием метода document.write() должен быть помещен в тег <script>, который выводится одновременно, иначе интерпретатор JavaScript не сможет распознать эти допустимые коды JavaScript и будет отображается как обычная строка в документе страницы. Например, следующий код будет отображать код JavaScript вместо его выполнения.
Скопируйте код кода следующим образом:
document.write('f();');
document.write('функция f(){');
document.write('alert(1);');
document.write(');');
Однако существуют определенные риски при выводе и выполнении скриптов через метод document.write(), поскольку разные движки JavaScript выполняют их в разном порядке, и при парсинге в разных браузерах могут возникать ошибки.
Ø Проблема 1: Невозможно найти переменные или функции, объявленные во внешнем файле JavaScript, импортированном с помощью метода document.write(). Например, посмотрите на пример кода ниже.
Скопируйте код кода следующим образом:
document.write('<script type="text/javascript" src="//www.VeVB.COm/test.js">
</script>');
document.write('<script type="text/javascript">');
document.write('alert(n);'); // IE сообщает, что переменная n не найдена
document.write('</script>');
alert(n+1); // Все браузеры сообщат, что переменная n не найдена;
Код внешнего файла JavaScript (test.js) выглядит следующим образом:
Скопируйте код кода следующим образом:
вар п = 1;
При тестировании в разных браузерах вы обнаружите синтаксическую ошибку и переменную n невозможно найти. Другими словами, если вы получаете доступ в блоке кода JavaScript к переменным, содержащимся во внешнем файле JavaScript, импортированном в выходные данные сценария, с помощью метода document.write() в этом блоке кода, будет отображена синтаксическая ошибка. При этом если в браузере IE не только в скрипте, но и в выходном скрипте выдаст сообщение о том, что выходную переменную, импортированную во внешний файл JavaScript, найти невозможно (выражение немного длинное и запутанное, читатели, которые не понимают, могут попробовать запустить приведенный выше код, чтобы его можно было понять).
Ø Вопрос 2. Разные механизмы JavaScript имеют немного разный порядок выполнения выходных сценариев внешнего импорта. Например, посмотрите на пример кода ниже.
Скопируйте код кода следующим образом:
<тип сценария="текст/javascript">
document.write('<script type="text/javascript" src="http://shaozhuqing.com/test1.js">
</script>');
document.write('<script type="text/javascript">');
document.write('alert(2);')
document.write('alert(n+2);');
document.write('</script>');
</скрипт>
<тип сценария="текст/javascript">
предупреждение (n+3);
</скрипт>
Код внешнего файла JavaScript (test1.js) показан ниже.
Скопируйте код кода следующим образом:
вар п = 1;
предупреждение (п);
Последовательность выполнения в браузере IE показана на рис. 1-6.
Рис. 1-6. Последовательность выполнения и синтаксические ошибки, выдаваемые браузером IE 7.
Последовательность выполнения в браузерах, соответствующих стандартам DOM, отличается от последовательности в браузерах IE, и на рис. 1-7 показана последовательность выполнения в браузере Firefox 3.0.
Рисунок 1-7. Последовательность выполнения браузера Firefox 3 и синтаксические ошибки.
Устраните разные порядки выполнения в разных браузерах и возможные ошибки. Мы можем поместить все внешние файлы, импортированные с помощью выходного сценария, в независимые блоки кода, чтобы этой проблемы можно было избежать в соответствии с порядком выполнения блоков кода JavaScript, представленным выше. Например, для приведенного выше примера вы можете спроектировать его следующим образом:
Скопируйте код кода следующим образом:
<тип сценария="текст/javascript">
document.write('<script type="text/javascript" src="//www.VeVB.COm/test1.js"></script>');
</скрипт>
<тип сценария="текст/javascript">
document.write('<script type="text/javascript">');
document.write('alert(2);') ; // Совет 2
document.write('alert(n+2);'); // Совет 3
document.write('</script>');
предупреждение(n+3); // Совет 4;
</скрипт>
<тип сценария="текст/javascript">
предупреждение(n+4); // Совет 5
</скрипт>
Таким образом, приведенный выше код может выполняться по порядку в разных браузерах, а порядок вывода — 1, 2, 3, 4 и 5. Причина проблемы: противоречие между выходным импортированным скриптом и текущим блоком кода JavaScript. Если выводить отдельно, конфликта не будет.