Зачем разделять тег <script>при записи его с помощью document.write ()? - PullRequest
259 голосов
/ 25 октября 2008

Почему некоторые сайты (или рекламодатели, которые предоставляют клиентам код 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>

Ответы [ 5 ]

362 голосов
/ 25 октября 2008

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

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

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

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

<script type="text/javascript">
    document.write('\x3Cscript type="text/javascript" src="foo.js">\x3C/script>');
</script>
30 голосов
/ 16 сентября 2013

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

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

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

20 голосов
/ 25 октября 2008

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

var newScript = document.createElement("script");
...
8 голосов
/ 25 ноября 2014

</script> внутри литерала строки Javascript интерпретируется 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>
8 голосов
/ 04 декабря 2013

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

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, чтобы продемонстрировать вариант использования. Надеюсь, это кому-нибудь пригодится!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...