防范JS全局命名空间中的HTML ID

时间:2014-01-26 10:29:52

标签: javascript requirejs

我在项目中使用Require.js.如果要定义模块,则将变量define添加到全局命名空间。

最近我有一个变量名称冲突[但奇怪的是,仅在Safari中],因为有一个ID为define的HTML标记,并且根据HTML5 specification

  

Window界面支持命名属性。随时支持的属性名称包括以下内容:

     
      
  • ...
  •   
  • ...
  •   
  • 活动文档中具有非空ID内容属性的任何HTML元素的id内容属性的值。
  •   

我认为用每个具有ID的HTML元素污染JS全局命名空间是一个糟糕的主意,但仅凭我的观点还不足以改变浏览器的行为方式。

在我的特定实例中,我发现this answer将包装Require.js;但从更广泛的意义上说:有没有办法防范规范中的这个细节?有没有一种技术可以防止这种GNS污染(没有明显的答案:“不要使用ID”)?至少可以通过JS控制台向开发人员(可能不是我)明白冲突吗?

1 个答案:

答案 0 :(得分:1)

HTML5的这种行为对RequireJS本身没有影响。我在Firefox和Chrome中运行了以下内容。正如预期的那样,全局空间中的define符号是RequireJS的定义函数。

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/xhtml; charset=utf-8"/>
  </head>
  <body>
    <p id="define">Paragraph.</p>
    <button id="redefine">Redefine</button>
    <script type="text/javascript">
      console.log("before requirejs:", typeof window.define);
    </script>
    <script type="text/javascript" src="js/require.js"></script>
    <script>
      require.config({
          baseUrl: "./js",
          paths: {
              jquery: 'jquery-1.10.2'
          },
      });
      console.log("requirejs loaded:", typeof window.define);
      require(["jquery"], function ($) {
          $("#redefine").click(function () {
              $("#define").replaceWith("<p id='define'>New paragraph.</p>");
              console.log("redefined:", typeof window.define);
              require(["foo"], function (foo) {
                  console.log(foo);
              });
          });
      });
    </script>
  </body>
</html>

我使用typeof来避免转储整个函数源。这足以达到我们的目的。 “重新定义”按钮用于模拟对DOM树的更改,人们可能认为该更改会覆盖window.define的值。 (模块foo是一个仅返回值"foo"的trival模块。)单击处理程序中的require表示RequireJS仍然有效。使用上面的代码,控制台的输出显示:

  1. 即使最初的window.define是DOM元素,RequireJS也会将define重新定义为自己的值。

  2. 一旦RequireJS定义了define,对DOM树的更改就不会改变它。

  3. 所以RequireJS不需要受到保护。

    但是那些坚持使用window.define来访问id为“define”的元素的代码呢?这样的代码有缺陷,应该修复。这个SO question很好地解决了这个问题。即使要求RequireJS避免触及全局define,依赖于window.define作为DOM元素的代码仍然会很脆弱。

      

    是否有防止此GNS污染的技术(没有明显答案:“不使用ID”)?

    除了明显的答案,没有。 (我使用“使用ID以外的东西”等同于“不使用ID”。)

      

    至少可以通过JS控制台向开发人员(可能不是我)发现冲突吗?

    JS虚拟机可能会检测到冲突,但我不知道是否会发生这种情况。

    但是Safari怎么样?

    这是Safari在JavaScript中处理全局变量的一个错误。没有其他浏览器能像Safari那样表现出来。

    This repository包含一组说明问题的文件。如果在Safari中加载,index.html文件将在控制台上显示失败。它在Firefox,Chrome,IE和Opera中运行良好。 test.html文件确定了问题。除Safari之外的所有浏览器都会在顶级作用域中将var foo之类的JavaScript中的变量声明视为遮蔽由于具有id属性集的元素而创建的同名变量。在除Safari之外的任何浏览器中加载,输出console.log的{​​{1}}将显示start of redefine:的变量值。在Safari中,它显示undefined undefined

    问题has been filed与RequireJS建议进行更改以解决此问题。

    如果建议的更改未通过,则解决方法是在加载RequireJS之前执行p#define p#define。没有必要再做任何事了。