如何封装第三方JavaScript文件,以免污染全局范围?

时间:2010-12-01 22:21:19

标签: javascript

我的一位客户问他们是否可以添加一些JavaScript来跟踪他们网站的用户行为。乍一看,我担心它会干扰网站上的其他第三方分析脚本,因为看起来双方都使用了相同的JavaScript压缩器。我不想梳理并搜索所有可能的命名冲突。 。

有没有办法可以包含第三方脚本(位于单独域中的脚本文件),但将它们包装在自己的命名空间中,或者为它们提供自己的范围,这样它们就不会与其他全局声明的变量和函数发生冲突?

4 个答案:

答案 0 :(得分:4)

为了隔离:

  1. (i)托管在不同域上的框架 - 无法直接交互
  2. 一个(i)在同一个域上托管的框架 - 只能通过显式窗口/框架引用进行交互
  3. 一个自动执行的匿名函数 - 交互很简单但行为良好的代码可以被隔离
  4. 无 - 希望没有人使用相同的变量或函数名称
  5. 这取决于第三方脚本,但我通常倾向于#2。可以进行交互,但是你不会受到偶然的document.write使用和全局命名空间污染的影响。

    编辑:#2

    的示例 page.html中的

    <div>...Your content...</div>
    <iframe src="tracker.html" 
        width="10" height="10" 
        style="position:absolute; top:-100px"></iframe>
    

    tracker.html(可选择全部)

    <script src="http://example.com/tracker.js"></script>
    

    这是基本结构,但需要更多设置,否则所有流量似乎都来自tracker.html。对于跟踪脚本,我建议将查询字符串中的顶级(真实)页面路径提供给iframe:“tracker.html?u = thispage.html”。您可以在服务器端或通过javascript设置查询字符串:

    page.html(再次)

    <div>...Your content...</div>
    <script>
        (function(){
            var iframe = document.createElement('iframe');
            iframe.src = 'tracker.html?u=' + escape(location.href);
            iframe.width = iframe.height = 1;
            iframe.style.position = 'absolute';
            iframe.style.top = '-100px';
    
            var nodes = document.getElementsByTagName('script');
            var s = nodes[nodes.length - 1];
            s.parentNode.insertBefore(iframe, s);
    
        })();
    </script>
    

    如果路径足以进行跟踪,您可以选择使用location.pathname而不是location.href(具有协议,域等)。

    毕竟...如果跟踪脚本来自信誉良好的来源(StatCounterGoogle Analytics等),我建议相信他们不要踩到你的页面变量和函数。选项1和2实际上适用于低信任情况。

答案 1 :(得分:3)

像这样:

(function() {
    // insert code here
})();

享受;)

答案 2 :(得分:2)

这应该不是问题。 Javascript压缩器不重命名全局变量(出于显而易见的原因),任何设计良好的脚本都不会暴露许多(任何)全局变量。如果他们希望您将其部署在您的页面上,他们有责任防止冲突。

答案 3 :(得分:1)

这取决于你想要做什么。

1)您希望以确定不会破坏脚本的方式加载页面中的第三方脚本。

你不能在这里做很多事 要求第三方做干净的脚本....一般情况下不太可能 在iframe中加载脚本....可能会使脚本无效

可能有办法,但这可能是愚蠢的:
通过ajax加载脚本(可能需要代理以避免跨域),用脚本内容(new Function('The content of the script');)创建一个JS函数,然后执行该函数(你也可以使用eval ...它是相同)。 这样,您可以管理为函数提供的参数,这样就可以保护全局变量。 这样做可能是打破第三方脚本的好方法。它会保护你吗?......也许吧。

无论如何,您还应该保护您免受第三方脚本的限制。每当您尝试使用在第三方脚本中声明的变量时,请始终检查是否已定义变量以确保脚本已加载。

2)您希望以不会被任何第三方脚本破坏的方式对脚本进行编码

首先:全局变量很危险。 你不知道是谁创造了它们,你不知道是谁修改了它们......不要相信它们。

您可以信任一个变量:全局范围内的this关键字。它应该是窗口对象,这个对象应该受到一点保护(至少应该是一个常量)。

如果你必须创建数组,字符串,regExp ...尽量不要使用“new Something()”的方式来做到这一点

var myArray = []; // not new Array();
var myRegExp = /^myRegExp$/; // not new RegExp('^myRegExp$');
var myString = 'myString'; // not new String('myString');

例如,可以覆盖Array变量。如果你使用[],你不会介意。

在某些情况下,你当然不能采取其他方式,但尽量不要这样做。

由于您不能信任全局变量,您还应该避免创建一些变量。仅创建绝对必要的全局变量。其他一切都应该是本地的。如果您的脚本不那么具有侵入性,那么其他人也可能尝试这样做。

要执行此操作(主要使用局部变量),您应该在“受保护区域”中工作。一个很好的方法是匿名自动执行功能。

(function () {
    // Your code here
}());

您还可以将全局变量传递给此“基本函数”。这可以有利于缩小和保护。您还可以获取“未定义”变量作为检查变量是否已定义的参考。

(function (window, alert, Array, undef) {
    // Your code here
    alert('I\'m safe here.');

    if([] instanceof Array) {
        alert('I\'ve got the real Array object');
    }

    if(window.jQuery === undef) {
        alert('jQuery not loaded');
    }

}(this, this.alert, this.Array));

我认为这样你的脚本应该受到一点保护。可能还有其他我忘记的事情,但这是一个好的开始。