Зачем расколоть тэг <script> при записи его с помощью document.write()?

Почему некоторые сайты (или рекламодатели, которые предоставляют код JavaScript javascript) используют метод разделения тегов <script> и/или </script> в пределах вызовов document.write()?

Я заметил, что Amazon делает это также, например:

<script type='text/javascript'>
  if (typeof window['jQuery'] == 'undefined') document.write('<scr'+'ipt type="text/javascript" src="http://z-ecx.images-amazon.com/images/G/01/javascripts/lib/jquery/jquery-1.2.6.pack._V265113567_.js"></sc'+'ript>');
</script>

Ответ 1

</script> должен быть разбит, потому что в противном случае он закончил бы закрытие блока <script></script> слишком рано. Действительно, он должен быть разделен между < и /, поскольку предполагается, что блок script (согласно SGML) будет завершен любым концом -tag open (ETAGO) (т.е. </):

Хотя элементы STYLE и script используют CDATA для своей модели данных, для этих элементов CDATA должен обрабатываться по-разному с помощью пользовательских агентов. Разметка и объекты должны рассматриваться как необработанные и передаваться в приложение как есть. Первое вхождение символьной последовательности "</" (разделитель открытого конца тега) рассматривается как завершение конца содержимого элемента. В действительных документах это будет конечным тегом для элемента.

Однако на практике браузеры заканчивают разбор блока CDATA script на фактическом теге </script> close.

В XHTML нет такой специальной обработки для блоков script, поэтому любой символ < (или &) внутри них должен быть &escaped; как в любом другом элементе. Однако браузеры, которые анализируют XHTML как HTML старой школы, будут запутаны. Существуют обходные пути с использованием блоков CDATA, но проще всего избегать использования этих символов без привязки. Лучшим способом записи элемента script из script, который работает на любом из парсеров, будет:

<script type="text/javascript">
    document.write('\x3Cscript type="text/javascript" src="foo.js">\x3C/script>');
</script>

Ответ 2

Вот еще один вариант, который я использовал, когда хочу сгенерировать тег script inline (поэтому он выполняется немедленно), не требуя каких-либо форм экранов:

<script>
    var script = document.createElement('script');
    script.src = '/path/to/script.js';
    document.write(script.outerHTML);
</script>

(Примечание: вопреки большинству примеров в сети, я не устанавливаю type="text/javascript" ни в теге, ни в приложении, ни в сгенерированном: браузер не имеет этого по умолчанию, поэтому он избыточен, но и не повредит, если вы не согласны).

Ответ 3

Я думаю, что это не позволяет интерпретатору HTML-браузера интерпретировать <script> , и, главным образом, </script> в качестве закрывающего тега фактического script, однако я не думаю, что использование document.write - отличная идея для оценки блоков script, почему бы не использовать DOM...

var newScript = document.createElement("script");
...

Ответ 4

Решение, которое Бобинс написал, отлично работает для меня. Я хотел предложить альтернативный метод для будущих посетителей:

if (typeof(jQuery) == 'undefined') {
    (function() {
        var sct = document.createElement('script');
        sct.src = ('https:' == document.location.protocol ? 'https' : 'http') +
          '://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js';
        sct.type = 'text/javascript';
        sct.async = 'true';
        var domel = document.getElementsByTagName('script')[0];
        domel.parentNode.insertBefore(sct, domel);
    })();
}

В этом примере я включил условную нагрузку для jQuery, чтобы продемонстрировать пример использования. Надеюсь, что это полезно для кого-то!

Ответ 5

</script> внутри строки Javascript litteral интерпретируется парсером HTML как закрывающий тег, вызывая неожиданное поведение (см. пример в JSFiddle).

Чтобы этого избежать, вы можете разместить свой javascript между комментариями (этот стиль кодирования был обычной практикой, когда Javascript плохо поддерживался среди браузеров). Это будет работать (см. Пример в JSFiddle):

<script type="text/javascript">
    <!--
    if (jQuery === undefined) {
        document.write('<script type="text/javascript" src="http://z-ecx.images-amazon.com/images/G/01/javascripts/lib/jquery/jquery-1.2.6.pack._V265113567_.js"></script>');
    }
    // -->
</script>

... но, честно говоря, использование document.write - это не то, что я считаю лучшей практикой. Почему бы не манипулировать DOM напрямую?

<script type="text/javascript">
    <!--
    if (jQuery === undefined) {
        var script = document.createElement('script');
        script.setAttribute('type', 'text/javascript');
        script.setAttribute('src', 'http://z-ecx.images-amazon.com/images/G/01/javascripts/lib/jquery/jquery-1.2.6.pack._V265113567_.js');
        document.body.appendChild(script);
    }
    // -->
</script>