我需要在我的网站上包含对第三方编写的JavaScript的引用。遗憾的是,编写此脚本的开发人员决定全局定义其所有功能。你知道,像这样:
function AwesomeStringHelper() {
// ...
}
function MyGreatFunction() {
// ...
}
当我使用<script>
标记引用此脚本时,这两种方法都将添加到window
对象中。
由于我不想污染全局范围,有没有办法可以更改外部脚本的范围?理想情况下,我希望能够引用类似于ExternalLibrary.MyGreatFunction()
等的这些方法。我无法修改第三方脚本,因为它是在外部托管的,并且它经常更改。
答案 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
}
});
});