如何在同一页面上隔离不同的javascript库?

如何在同一页面上隔离不同的javascript库?,javascript,isolation,Javascript,Isolation,假设我们需要在第三方页面中嵌入一个小部件。例如,这个小部件可能使用jquery,所以小部件本身带有一个jquery库。 假设第三方页面也使用jquery,但版本不同。 嵌入小部件时如何防止它们之间的冲突?jquery.noConflict不是一个选项,因为它需要为页面中加载的第一个jquery库调用此方法,这意味着第三方网站应该调用它。这个想法是,第三方网站不应该为了使用它而修改或做任何事情,除了把带有src的标签放到小部件上 另外,这不是jquery的特别问题——谷歌闭包库(甚至是编译过的)可

假设我们需要在第三方页面中嵌入一个小部件。例如,这个小部件可能使用jquery,所以小部件本身带有一个jquery库。 假设第三方页面也使用jquery,但版本不同。 嵌入小部件时如何防止它们之间的冲突?jquery.noConflict不是一个选项,因为它需要为页面中加载的第一个jquery库调用此方法,这意味着第三方网站应该调用它。这个想法是,第三方网站不应该为了使用它而修改或做任何事情,除了把带有src的标签放到小部件上

另外,这不是jquery的特别问题——谷歌闭包库(甚至是编译过的)可以作为一个例子

除了iframe之外,还有哪些解决方案可以隔离不同的javascript库?
也许将javascript作为字符串加载,然后使用eval(通过使用函数('code to eval'),而不是在匿名函数中使用eval('code to eval'))它就可以做到这一点?

你可以在jQuery上调用Google API的完整URL,这样它就可以在应用程序中工作了,我想这正是你想用的。如果我理解正确,您的代码应该如下所示:

(function () {
var my$;

// your copy of the minified jQuery source

my$ = jQuery.noConflict(true);
// your widget code, which should use my$ instead of $
}());
调用
noConflict
将把全局
jQuery
$
对象恢复为它们以前的值

函数(…)
在函数内部进行评估,这不会更好

为什么不使用
iframe
它们为第三方内容提供默认沙盒


对于友好的用户,您可以使用现代浏览器的
parent.postMessage
或老年人的
window.name
hack在用户和页面之间共享文本数据。

我建立了一个库来解决这个问题。当然,我不确定它是否会对您有所帮助,因为代码仍然必须意识到问题并首先使用库,因此只有当您能够更改代码以使用库时,它才会有所帮助

该库被调用,可以免费下载和使用,因为它是在知识共享许可下的开源库

它基本上是通过将代码打包到函数中来工作的。从这些函数中导出要向其他包公开的对象。在使用者软件包中,您将这些对象导入本地命名空间。不管别人或者你自己是否多次使用同一个名字,因为你可以解决歧义

以下是一个例子:

(文件示例/greeting.js)

(文件示例/ambiguity.js)

(文件示例/ambiguitytest.js)

example/ambiguitytest.js使用两个库,它们都导出函数,但它可以显式地导入正确的函数,并将它们指定给本地别名以消除它们之间的歧义

以这种方式使用jQuery意味着通过将jQuery的代码包装在对Package的调用中并导出它现在公开给全局范围的对象来“打包”jQuery。这意味着对库进行一点更改,这可能不是您想要的,但遗憾的是,如果不借助iFrame,我将无法看到这一点

我计划在下载时加入流行库的“打包”版本,jQuery肯定在列表中,但目前我只有一个打包版本的Sizzle,jQuery的选择器引擎。


<script src="myjquery.min.js"></script>
<script>window.myjQuery = window.jQuery.noConflict();</script>
...
<script src='...'></script> //another widget using an old versioned jquery
<script>
(function($){
    //...
    //now you can access your own jquery here, without conflict
})(window.myjQuery);
delete window.myjQuery;
</script>
window.myjQuery=window.jQuery.noConflict(); ... //另一个使用旧版本jquery的小部件 (函数($){ //... //现在您可以在这里访问自己的jquery,而不会产生冲突 })(window.myjQuery); 删除window.myjQuery;
最重要的一点是:

  • 在您自己的jQuery和相关插件标记之后立即调用jQuery.noConflict()方法

  • 将结果jquery存储到一个全局变量中,使用一个几乎不会发生冲突或混淆的名称

  • 使用旧版本的jquery加载小部件

  • 接下来是你的逻辑代码。使用闭包获取私人美元以获得便利。私有$不会与其他jquery冲突

  • 您最好不要忘记删除全局临时变量

  • “将javascript加载为字符串,然后对其进行评估”的想法有多么糟糕,我怎么强调都不过分,只是……不要,还有更多的理由不这么做。这是一个有趣的问题,在每个组件平台(DLL、COM、托管代码)中都会反复出现。这不是您的组件损坏的情况,您需要将其更新到最新的库。这是一个真正的问题,我想看看如何用动态语言解决它。尼克,你是对的,但我说的eval实际上是指使用函数(“代码到eval”),而不是eval(“代码到eval”)本身。我将更新我的问题。情况并非总是如此-应用程序可能发布在禁止访问Google API URL的公司内部网中。这并没有解决实际问题,即这两个版本都将尝试绑定到window.$和window.jQuery。他要求的代码没有冲突,所以我给出了这个想法。我不知道是什么错了,这是另一个坏主意,因为一个网站可能是在jquery 1.3.2上创建的,而我的插件使用了jquery 1.7.x。这些变化是巨大的,会破坏最初的网站,因为大多数方法都过时了,或者完全做了其他事情。隔离是插件注入的唯一方式。问题是,如果第三个应用程序将使用noConflict加载jquery,并且该版本将与我预期使用的版本不兼容。实际上,不,考虑到我草拟的解决方案,这不是问题。您的代码在匿名函数的作用域中引用my$变量(实际上可以命名为$)。第三个应用程序在该范围之外所做的更改不会对其值产生任何影响。+1这当然是jQuery处理此问题的方法,但是它很烦人
    Package("example.ambiguity", function() {
      // functions hello and goodbye are also in example.greeting, making it ambiguous which
      // one is intended when using the unqualified name.
      function hello() {
        return "Hello ambiguity!";
      };
    
      function goodbye() {
        return "Goodbye ambiguity!";
      };
    
      // export for use by other packages
      Export(hello);
      Export(goodbye);
    });
    
    Package("example.ambiguitytest", ["example.ambiguity", "example.greeting"], function(hello, log) {
      // Which hello did we get? The one from example.ambiguity or from example.greeting?
      log().info(hello());  
      // We will get the first one found, so the one from example.ambiguity in this case.
    
      // Use fully qualified names to resolve any ambiguities.
      var goodbye1 = Import("example.greeting.goodbye");
      var goodbye2 = Import("example.ambiguity.goodbye");
      log().info(goodbye1());
      log().info(goodbye2());
    });
    
    <script src="myjquery.min.js"></script>
    <script>window.myjQuery = window.jQuery.noConflict();</script>
    ...
    <script src='...'></script> //another widget using an old versioned jquery
    <script>
    (function($){
        //...
        //now you can access your own jquery here, without conflict
    })(window.myjQuery);
    delete window.myjQuery;
    </script>