我正在寻找将对象内容导入全局范围的内容:
var y = {}
y.x = 5
//do some magic here
console.log(x); //5
我想这样做是因为我可以制作一个易于使用的模块,具有令人难忘的功能名称,而不必担心被其他模块意外覆盖的事情。
考虑这个例子:
funModule = {};
funModule.washClothes = function(clothes){...}
funModule.walkDog = function(dogName){...}
//etc
funModule.UNITED_STATES_DEFICIT = ...;
这里我创建了一个具有一些有用功能和常量的模块(实现和值被替换为“...”)。
我不希望我的用户每次调用函数或使用常量时都必须键入模块名称。这将导致非常混乱的代码:
funModule.walkDog(funModule.UNITED_STATES_DEFICIT);
我可以通过全局定义所有内容再次尝试:
washClothes = function(clothes){...}
walkDog = function(dogName){...}
//etc
UNITED_STATES_DEFICIT = ...;
但是如果另一个模块也定义了通常命名的函数washClothes
,我们就遇到了麻烦。 (在我的实际情况中,通常命名的函数是run
)
从技术背景中删除,这是我面临的问题:
首先,我想使用简单易记的名称,使模块易学易用。
其次,我不希望简单的名称使模块无法与其他人一起使用。特别是随着它的增长,将使用许多常用名称。如果用户可以决定是否直接导入名称,那就太好了。
第三,我意识到我正在输入这个,我所描述的内容肯定已经存在,在python中。有关详细信息,请参阅http://effbot.org/zone/import-confusion.htm。
tl; dr如何使用javascript完成类似python的导入?
编辑:
似乎没有通用的方法来做到这一点。
这个问题与this one不同,因为它不是关于Node.js.我一直在寻找一种通用的方法,但这似乎不太可能,所以我将它限制在网络浏览器上(即chrome,firefox,safari,opera,也许就是这样)
编辑:
这篇关于范围的一般文章可能对任何有类似问题的人有用:https://toddmotto.com/everything-you-wanted-to-know-about-javascript-scope/
答案 0 :(得分:1)
ES6 Modules是你想要的。 如果您将对象定义为es6模块,则可以执行此操作(使用示例中的名称):
import { washClothes } from "fun-module";
然后washClothes
将在导入它的文件上全局可用,就像您想要的那样。
如果您真的需要像帖子中的评论那样的神奇解决方案,并且不想使用ES6并且您在浏览器中运行,则可以将其放在窗口对象上:
window.x = 5
答案 1 :(得分:1)
在JavaScript中,至少在浏览器中,全局变量是client.send('foobar');
对象的属性:即window
和window.x
(其中x
是全局的)参考相同的价值。因此,理论上,您可以使用Object.assign()
将对象的属性复制到x
对象,使其成为全局变量。这大致相当于Python中的window
。
但正如globals().update(myobj.__dict__)
在Python中通常是一个坏主意一样,这听起来也是一个坏主意,除非更糟糕,因为import *
还有很多其他属性,你可能不会这样做。我想要破坏。
答案 2 :(得分:1)
Object.prototype.makeglobal=function(){
for(key in this){
if(window[key]){//replace window if youre not in a browser
//already exist, error handling
console.error(key+' already exist in window');
}else{
window[key]=this[key];
}}};
像这样使用:
funModule.makeglobal();
//now you can
washClothes();
但这很糟糕,因为它污染了全球对象。
2.您的用户应该创建自己的命名空间:
function(){
this.washClothes();
//more of his content
}.call(funModule);
3.您还可以添加加载程序:
funModule.load=function(func){
console.log(func);
console.log(this);
func.call(this,this);
};
现在你可以做到:
funModule.load(function(fun){
this.washClothes();
fun.washClothes();
});
4.如果您担心可读性,可以使用功能链(?):
funModule.washClothes=function(){
//your code
return this;
}
现在你可以这样做:
funModule.washClothes("tshirts").washClothes("trousers").washClothes();
答案 3 :(得分:0)
经过一些额外的研究后,我找到了一种方法,可以在不污染全局命名空间的情况下,允许用户直接访问模块内容。
此解决方案允许用户:
*此功能附带一个捕获
这是代码
funModule = {};
//This stuff is the arbitrary contents of the module:
funModule.washClothes = function(clothes){...}
funModule.walkDog = function(dogName){...}
//etc
funModule.UNITED_STATES_DEFICIT = ...;
//etc
//This part is necessary:
funModule.run(userApp)
{
for(key in this){
eval(key + " = " + this[key] + ";");
}
userApp();
}
在funModule.run的范围和funModule中动态定义函数的唯一方法(我能找到)是使用Eval。使用call,apply或bind来操作范围仍然需要使用this
关键字,这种不寻常风格的重点是使客户端代码尽可能简单且不重复。
function myApp()
{
washClothes(UNITED_STATES_DEFICIT);
}
funModule.run(myApp);
在客户端代码中,可以直接访问除funModule.run
之外的所有内容。因此全局命名空间保持干净,但用户的代码不需要不必要的重复。
function myApp()
{
washClothes(UNITED_STATES_DEFICIT);
}
funModule.run( otherModule.run.bind({},myApp) ); //otherModule has precedence here
假设otherModule
是一个具有相同run
功能的不同模块。 funModule
将加载其内容,然后调用其第一个参数。第一个参数将加载otherModule
的内容,覆盖funModule
中具有相同名称的任何内容。
function myApp()
{
//directly access stuff from funModule
walkDog()
var big = UNITED_STATES_DEFICIT * 3.14;
//explicitly access stuff from specific modules
clothes = new otherModule.Clothes();
funModule.washClothes(otherModule.washClothes(clothes));
}
funModule.run(myApp)
这是使用eval
所必需的功能。用户可以选择不使用直接访问的模糊性。他们仍然可以通过命名它们来自的模块来访问属性/方法。
一些StackOverflow用户可以理解地关注问题中不寻常的约束条件,所以我想我会回答以下问题:
为什么不为模块使用短别名。
我试图在this article中回答这个问题,该问题来自于这个问题和答案。