在预先存在的命名空间中定义所有外部 JavaScript
Define all external JavaScript in a pre-existing namespace
我完全意识到 eval 等的危险,所以请不要浪费时间评论这些黑客是如何被黑客攻击的。
假设我正在使用第三方 JavaScript 库,但我希望它的所有代码都在特定命名空间中定义......我也无法控制。例如:
<script src="http://example.com/library.js>
<!-- library.js contains:
var x = 0;
function foo() {}
-->
我希望能够在命名空间Bar
的上下文中定义x
和foo
,而不是全局上下文(window
)。
假设定义了Bar
,但在另一个我无法控制的外部 js 文件中,我尝试了一些技巧,例如:
<script>
var externalCode = $.ajax("http://example.com/library.js");
eval.call(Bar, externalCode);
// and also tried:
(function(str){ eval(str); }).call(Bar, externalCode);
</script>
但是我无法访问Bar.x
也无法调用Bar.foo()
.
基本上,我想实现如果我将 library.js 的内容粘贴到我的 Bar
命名空间中会得到的结果,一个 la:
var Bar = {
x: 0,
foo: function() {}
}
但是,当我也无法控制Bar
命名空间时,我正在尝试执行此操作。因此,我无法"复制和粘贴"。另一个相关的例子是我们如何在 Ruby 中将新方法"打入"预先存在的类定义中。
最后,我的具体用例是我尝试将 p5.js 中的所有内容"注入"到 Opal
命名空间中。
适用于当今浏览器的简单解决方案是:
<script src="http://example.com/library.js>
<!-- library.js contains:
var x = 0;
function foo() {}
-->
<script>
$.ajax('/library.js', function(jsString) {
var wrapped = `function() {
${jsString};
Bar.x = x;
Bar.foo = foo;
}();`
eval(wrapped);
});
</script>
但是,不需要列出模块的解决方案是 EcmaScript 6 模块。如果您使用 https://babeljs.io/转译它,它可以与当今的浏览器一起使用。
//------ main.js ------
import * as Bar from 'lib';
console.log(Bar.foo()); // no error
console.log(Bar.x); // 0
如果你需要它今天在所有浏览器中工作,并且不想转译你的代码,你需要第一个示例,它可以概括为
function importIntoNs(ns, scriptUrl, symbolNames) {
$.ajax(scriptUrl, function(jsString) {
var wrapped = `(function() {
${jsString};`;
symbolNames.forEach(symbolName => {
wrapped += 'this.' + symbolName + ' = symbolName;'n' ;
});
wrapped += '})';
eval(wrapped).apply(ns);
}
}
importIntoNs(Bar, 'http://example.com/library.js', ['x', 'foo']);
如果有人因为 eval 而想投反对票,请记住,无论他们是否将其放入 <script>
标签中,OP 都已经将执行脚本。
这是一个无需获取脚本的工作示例。
function importScriptIntoNs(ns, jsString, symbolNames) {
var addSymbols = '';
symbolNames.forEach(symbolName => {
addSymbols += 'this.' + symbolName + ' = ' + symbolName + ';'n';
});
var wrapped = `(function() {;
${jsString}
${addSymbols}
})`;
eval(wrapped).apply(ns);
}
var Bar = {};
var jsString = `
var x = 'It works';
function foo() {alert(x)}
`;
importScriptIntoNs(Bar, jsString, ['x', 'foo']);
Bar.foo()
在不污染全局作用域的情况下处理库和其他依赖项的一种方法是使用某种异步模块定义。我喜欢使用和推荐的一个很好的是 Require.js。
它背后的整个想法是,您可以将库和依赖项捆绑到模块中,并在需要时调用它们,而无需简单地在全局范围内加载所有内容。
下面是如何在您的情况下使用它的示例:
require(['http://example.com/library.js'], function(Bar){
// library.js is now bound within this scope under the alias Bar
});
- 如何在定义js文件后为外部javascript文件设置变量
- 像createComment这样的各种自定义变量名在内联javascript中被覆盖,但在外部js中没有.为什么?
- 定义函数时,如何捕获外部变量的当前值
- Rally SDK外部开发Rally环境未定义
- 函数从$(document).ready外部调用在$(document).ready中定义的函数
- JavaScript未定义的函数外部JavaScript文件
- 取消重置由外部样式表定义的样式
- JavaScript-如何将onload函数内部定义的变量取到外部
- 为什么嵌套的 describe() 块不能看到在外部块中定义的变量
- 调用插件外部的自定义函数并传递参数
- 得到"未定义“;从外部javascript加载函数
- 无法读取属性'来自JS'外部viewmodel.js中未定义的
- 加载外部脚本时,匿名定义()模块不匹配
- 使用外部单击关闭自定义指令弹出框
- 在预先存在的命名空间中定义所有外部 JavaScript
- 如何在 AngularJS 中将自定义指令与外部 HTML 模板捆绑在一起
- 从外部文件在打字稿中声明变量得到引用错误:..未定义
- 使用调试器从内部函数调用外部函数中定义的变量
- 为什么不在对象外部使用属性定义语法是语法错误
- 定义外部JS文件的执行上下文