将外部Javascript与定义全局(窗口)范围中的方法隔离

时间:2016-10-12 15:49:54

标签: javascript

我需要在我的网站上包含对第三方编写的JavaScript的引用。遗憾的是,编写此脚本的开发人员决定全局定义其所有功能。你知道,像这样:

function AwesomeStringHelper() {
  // ...
}

function MyGreatFunction() {
  // ...
}

当我使用<script>标记引用此脚本时,这两种方法都将添加到window对象中。

由于我不想污染全局范围,有没有办法可以更改外部脚本的范围?理想情况下,我希望能够引用类似于ExternalLibrary.MyGreatFunction()等的这些方法。我无法修改第三方脚本,因为它是在外部托管的,并且它经常更改。

5 个答案:

答案 0 :(得分:5)

如果您的第三方模块直接分配给window对象(例如window.myGlobal = someValue),,您可以手动下载源代码,那么您应该能够将整个脚本“包装”在一个函数中,window对象已被重载:

function wrapModule(code) {
  // create a "fake" window object that inherits from the global object
  var fakeWindow = Object.create(window);

  // create a function wrapping the code
  // note that "window" is a parameter name in this function, shadowing
  // the global object
  var func = Function("window", code);

  // call function
  func.call(fakeWindow, fakeWindow);

  // return fake window object
  return fakeWindow;
}

// run code
const fakeWindow = wrapModule(`
  var x = 0;    // local variable (will not be exported)
  y = 1;        // global variable (will still be leaked)
  window.z = 2; // assignment to window
  this.w = 3;   // assignment to this
`);

// check what variables are exposed
console.log('window.x', typeof x); // window.x undefined
console.log('window.y', typeof y); // window.y number
console.log('window.z', typeof z); // window.z undefined
console.log('window.w', typeof w); // window.w undefined

// check what variables are exposed in fakeWindow
console.log('fakeWindow.x', typeof fakeWindow.x); // fakeWindow.x undefined
console.log('fakeWindow.y', typeof fakeWindow.y); // fakeWindow.y number
console.log('fakeWindow.z', typeof fakeWindow.z); // fakeWindow.z number
console.log('fakeWindow.w', typeof fakeWindow.w); // fakeWindow.w number

答案 1 :(得分:5)

首先,尝试将第三方开发人员告知如何正确编写模块。

如果这不起作用,请执行:

var ExternalLibrary = ExternalLibrary || window;

位于代码顶部。

然后,您可以使用ExternalLibrary.MyGreatFunction()来引用它们的功能(即使它们在全局window范围内仍然可见),然后在第三方开发人员修复其范围问题之后再进行大多数情况下,您需要进行一行更改以保持兼容性(或者,如果它们碰巧使用与您相同的ExternalLibrary名称,则根本不需要更改)。

或者,在<script>标记的任一侧使用两个简单的代码片段,它们记住window对象的键,然后将新出现的键移动到新对象中(同时删除他们来自window):

预载荷:

var ExternalLibrary = { _current: Object.keys(window) };

后负载:

Object.keys(window).forEach(function(key) {
    if (ExternalLibrary._current.indexOf(key) < 0) {
        ExternalLibrary[key] = window[key];
        delete window[key];
    }
});
delete ExternalLibrary._current;

我过去曾使用类似的方法(在严格模式通用之前)来检查泄漏的全局变量。

答案 2 :(得分:1)

假设您知道正在定义的特定函数,那么在加载脚本之后,这不起作用吗?

const ThirdPartyLib = {AwesomeStringHelper, MyGreatFunction};
delete window.AwesomeStringHelper;
delete window.MyGreatFunction;

ThirdPartyLib.AwesomeStringHelper(haveFun);

答案 3 :(得分:0)

您可以将整个脚本包装在一个函数中,并使用&#34; public&#34;返回一个对象。你想要的功能,它可能很乏味,很难维护。

var myLib = function() {
   //entire script
   return {
       functionA : functionA,
       functionB : functionB,
       //rest of functions
   }
}

或者像这样(中间调用的函数)

(function(global) {
    //entire script
    myLib.functionA = functionA;
    myLib.functionB = functionB;
    //rest of fn
    global.myLib = myLib;

})(window);

您可以使用gulp自动执行此操作,我不确定是否有适合此功能的插件。

答案 4 :(得分:0)

不确定jQuery是一个选项还是你关心它但我不知道如何编写本机JS AJAX调用所以请耐心等待:

$(document).ready(function(){
    $.ajax({
        url: 'www.example.com/awesome_script.js', // get the contents of the external script
        type: 'GET',
        crossDomain: true,
        dataType: 'html',
        success: function(data){
            // build our script tag and wrap the contents inside of a function call
            var script = "<script>"
                script+= "var callMe = function(call_func, var1, var2, var3){";
                script+= data;
                script+= "return typeof call_func === 'function' ? call_func(var1, var2, var3) : 'You trying to dynamically call a variable? idk how to do that.';";
                script+= "};";
                script+= "<\/script>";

            // assuming this is legal then just append the custom script tag to the <body> :-)
            $('body').append($(script)[0]);

            // profit?
            callMe('AwesomeStringHelper', 'some_var'); // this function accepts one parameter
            callMe('MyGreatFunction'); // this function accepts no parameters
        }
    });
});