为什么在用 document.write() 编写时将 <script> 标签拆分?

IT技术 javascript html
2021-01-21 02:39:49

为什么某些网站(或为客户提供 JavaScript 代码的广告商)采用调用中拆分<script>和/或</script>标记的技术document.write()

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

<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个回答

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

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

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

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

<script type="text/javascript">
    document.write('\x3Cscript type="text/javascript" src="foo.js">\x3C/script>');
</script>
@Mathias:<\/script>在这种情况下很好,但它只能在 HTML 中工作;在没有额外的 CDATA 部分包装的 XHTML 中,它仍然是一个格式良好的错误。您还可以\x3C在内联事件处理程序属性中使用<HTML 和 XHTML 中也无效的属性,因此它具有更广泛的适用性:如果我选择一种易于自动化的方法来转义所有上下文的 JS 字符串文字中的敏感字符,那就是我想要的那个。
2021-03-10 02:39:49
我不认为转义开头 < 是必要的......document.write('<script src="foo.js">\x3C/script>')在所有浏览器中似乎都足够回到 IE6。(我省略了 type 属性,因为它在 HTML5 中不是必需的,也不是按照任何浏览器的要求强制执行的。)
2021-03-24 02:39:49
@MathiasBynens-document.write无关紧要,它恰好是示例。OP 可以使用innerHTML,这是关于隐藏</标记解析器中隐藏的字符序列,无论它出现在哪里。只是大多数解析器在严格不应该的情况下在脚本元素中容忍它(但 HTML 解析器非常容忍)。你是对的,尽管这<\/在 HTML 的所有情况下都足够了。
2021-04-06 02:39:49
\/是一个有效的转义序列/,那么为什么不直接使用它来代替那些字符串文字转义<呢?例如document.write('<script src=foo.js><\/script>');此外,</script>不是唯一可以关闭<script>元素的字符序列这里有更多信息:mathiasbynens.be/notes/etago
2021-04-09 02:39:49
在 HTML 中,<可用于内联事件处理程序属性。html5.validator.nu/...你对\x3Csich的 XHTML 兼容性是正确的,但由于 XHTML 不支持document.write(或innerHTML) 反正我不明白这有什么关系。
2021-04-09 02:39:49

这是我在想要生成内联脚本标记(因此它立即执行)而不需要任何形式的转义时使用的另一个变体:

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

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

这个比公认的答案要好,因为这种变化实际上可以缩小。这个 'x3C/script>' 将在缩小后变成 '</script>'。
2021-04-06 02:39:49
好点:类型。从 HTML5 开始,默认值被定义为“text/javascript”,因此它是一个无用的属性。w3.org/html/wg/drafts/html/master/...
2021-04-08 02:39:49

我认为是为了防止浏览器的 HTML 解析器解释 <script>,主要是 </script> 作为实际脚本的结束标记,但是我不认为使用 document.write 是评估脚本的好主意块,为什么不使用 DOM...

var newScript = document.createElement("script");
...
有必要防止解析器过早关闭脚本块......
2021-03-17 02:39:49

</script>HTML 解析器将 Javascript 字符串内部解释为结束标记,从而导致意外行为(参见 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>
这看起来比手动拆分字符串更通用。例如,如果字符串是由模板引擎插入的,则拆分是不可行的。
2021-03-13 02:39:49
抱歉,我的错误:我写的append不是appendChild. 更正了答案。感谢您的关注!
2021-03-25 02:39:49
如果你想使用纯 JS,你仍然需要使用 document.write ;)
2021-03-27 02:39:49
抱歉,我想写 - 这需要 jQuery 库,对吗?当我使用 document.body.append 时,它抛出了一个错误,即 document.body.append 不是一个函数。
2021-03-28 02:39:49

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 包含了一个条件加载来演示用例。希望这对某人有用!

救了我!使用 document.write(<script>) 时,我的网站显示空白屏幕。这奏效了。
2021-03-31 02:39:49
@dmp 除非从协议为 file:// 的文件系统运行
2021-04-01 02:39:49
无需检测协议 - 无协议 URI 工作正常('//foo.com/bar.js' 等)
2021-04-07 02:39:49
也不需要设置异步。它为所有动态创建的脚本标签设置。
2021-04-07 02:39:49