如何在javascript

时间:2016-12-26 19:48:32

标签: javascript syntax

我正在寻找将对象内容导入全局范围的内容:

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的导入?

编辑:

似乎没有通用的方法来做到这一点。

  • 使用Window不适用于所有环境(但可以在任何常用浏览器中使用)。
  • 显然,ES6模块不能直接用于Web浏览器。

这个问题与this one不同,因为它不是关于Node.js.我一直在寻找一种通用的方法,但这似乎不太可能,所以我将它限制在网络浏览器上(即chrome,firefox,safari,opera,也许就是这样)

编辑:

这篇关于范围的一般文章可能对任何有类似问题的人有用:https://toddmotto.com/everything-you-wanted-to-know-about-javascript-scope/

4 个答案:

答案 0 :(得分:1)

ES6 Modules是你想要的。 如果您将对象定义为es6模块,则可以执行此操作(使用示例中的名称):

import { washClothes } from "fun-module";

然后washClothes将在导入它的文件上全局可用,就像您想要的那样。

Read about it here

如果您真的需要像帖子中的评论那样的神奇解决方案,并且不想使用ES6并且您在浏览器中运行,则可以将其放在窗口对象上:

window.x = 5

答案 1 :(得分:1)

在JavaScript中,至少在浏览器中,全局变量是client.send('foobar'); 对象的属性:即windowwindow.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)

经过一些额外的研究后,我找到了一种方法,可以在不污染全局命名空间的情况下,允许用户直接访问模块内容。

此解决方案允许用户:

  1. 编写直接引用模块的功能/属性
  2. 的代码
  3. 如果有多个模块以相同的样式编写,则定义优先级
  4. 仍按模块名称*
  5. 访问模块的功能/属性

    *此功能附带一个捕获

    这是代码

    模块

    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关键字,这种不寻常风格的重点是使客户端代码尽可能简单且不重复。

    客户代码1

    function myApp()
    {
        washClothes(UNITED_STATES_DEFICIT);
    }
    funModule.run(myApp);
    

    在客户端代码中,可以直接访问除funModule.run之外的所有内容。因此全局命名空间保持干净,但用户的代码不需要不必要的重复。

    客户代码2

    function myApp()
    {
        washClothes(UNITED_STATES_DEFICIT);
    }
    funModule.run( otherModule.run.bind({},myApp) );  //otherModule has precedence here
    

    假设otherModule是一个具有相同run功能的不同模块。 funModule将加载其内容,然后调用其第一个参数。第一个参数将加载otherModule的内容,覆盖funModule中具有相同名称的任何内容。

    客户代码3

    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中回答这个问题,该问题来自于这个问题和答案。