为什么有些网站(或给客户提供javascript代码的广告商)在document.write()调用中使用一种技术将<script>和/或</script>标记分开?

我注意到亚马逊也这样做,例如:

<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>

当前回答

下面是我在不需要任何形式的转义而想要内联生成脚本标记时使用的另一种变体:

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

(注:与网络上的大多数例子相反,我没有在封闭标签上设置type="text/javascript",也没有生成的标签:没有浏览器不将其作为默认值,所以它是多余的,但也不会伤害,如果你不同意)。

其他回答

</script>必须被分解,否则它将过早地结束封闭的<script></script>块。实际上,它应该在<和/之间分割,因为脚本块(根据SGML)应该被任何结束标记打开(ETAGO)序列(即</)终止:

虽然STYLE和SCRIPT元素使用CDATA作为它们的数据模型,但是对于这些元素,用户代理必须以不同的方式处理CDATA。标记和实体必须被视为原始文本,并原样传递给应用程序。字符序列“</”(结束标记打开分隔符)的第一次出现被视为终止元素内容的结束。在有效的文档中,这将是元素的结束标记。

然而,实际上浏览器只在</script>关闭标记上结束对CDATA脚本块的解析。

在XHTML中,脚本块没有这样的特殊处理,因此其中的任何<(或&)字符必须被&转义;就像其他元素一样。然而,将XHTML解析为老式HTML的浏览器将会感到困惑。有一些涉及CDATA块的变通方法,但最简单的方法是避免使用这些未转义的字符。从适用于任何类型解析器的script中编写一个script元素的更好方法是:

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

我认为是为了防止浏览器的HTML解析器解释<script>,主要是</script>作为实际脚本的结束标记,但我不认为使用文档。写是一个很好的想法来评估脚本块,为什么不使用DOM…

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

Javascript字符串文字中的</script>被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>

...但是说实话,使用文档。写作并不是我认为的最佳实践。为什么不直接操作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>

下面是我在不需要任何形式的转义而想要内联生成脚本标记时使用的另一种变体:

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

(注:与网络上的大多数例子相反,我没有在封闭标签上设置type="text/javascript",也没有生成的标签:没有浏览器不将其作为默认值,所以它是多余的,但也不会伤害,如果你不同意)。

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的条件加载来演示用例。希望这对某些人有用!