JavaScript本地变量声明

8

基本上这是一个如何访问局部作用域处理程序的问题。我正在尝试实现类似于全局变量定义的功能,例如:

window['newObject'] = "some string";
alert(newObject);

但是只适用于本地范围。目前我唯一的解决方案是使用evals:

eval("var newObject='some string'");

但这真的是一个丑陋的解决方案...最好的解决方案就像使用一些本地作用域的引用,就像在window[]解决方案中一样,但我从未听说过任何对本地作用域的引用...有什么想法吗?

示例如下:

function x(arg)
{
   localScope[arg.name]=arg.value;
   alert(sex);
}

x({name:"sex", value:"Male"});

我明白了,你的意思是是否有JavaScript等价于PHP的“变量变量”。http://www.php.net/manual/en/language.variables.variable.php - Jason S
可能是JavaScript:通过名称字符串动态获取本地变量的重复问题。 - Michał Perłakowski
8个回答

6
你需要的是所谓的“调用对象”。但是根据这里所述,您无法直接访问它,所以您运气不好。

我以前从未听说过“调用对象”这个术语,但你提供的链接很有用。它似乎是JavaScript实现细节,用于描述函数的局部作用域(可以通过被捕获在闭包中而逃脱“局部”作用域)。然而,我认为这与原始问题没有太多关系。 - Tom Lokhorst
转念一想,如果您确实可以直接访问该实现细节,那么它将与问题相关,所以在这方面您是正确的。 - Tom Lokhorst
好的,如果你愿意,你可以做他要求的事情:“localScope[name]=value;” - JW.

1

我一定是漏掉了什么。你想要的东西和只做以下操作有何不同:

 var newObject = 'some string';

我认为没有办法做到你所要求的。可以使用本地对象的成员,例如:

function doSomething(name, value)
{
  var X = {};
  X[name] = value;
  if (X.foo == 26)
    alert("you apparently just called doSomething('foo',26)");
}

如果您选择一个像$或X这样的1个字符变量,则“花费”2个字符(变量名称加上一个点),并避免尝试使用eval或执行一些奇怪的操作。

是的 - 我想根据我接收到的数据动态地执行这个函数。 - Paweł Witkowski Photography
我是指 - 是的,你在那里遗漏了一些东西。我需要动态定义一个本地变量 ;) - Paweł Witkowski Photography

1
为什么不在本地范围内创建一个对象,然后将其用作您希望动态创建的任何变量的容器呢?
function x(arg)
{
    var localSpace = {};
    localSpace[arg.name] = arg.value;
}

但是我需要能够仅使用名称引用元素,而不是在每个变量之前使用localSpace [name] ... - Paweł Witkowski Photography
因为第三方希望在模板中引用其本地作用域的值... 好吧,解释这个真的很复杂,但我可以确定,唯一的方法就是扩展本地作用域(或全局作用域,但需要更长时间访问变量)。 - Paweł Witkowski Photography

1

好的,我找到了一个相关问题,正是我需要的……

如何在 JavaScript 中动态访问本地作用域?

我记得在 ECMA 262 中只有一种方法可以使用 "with" 语句(当然还有 eval 方法)来动态添加局部变量到作用域中,以下是解决方案:

var x=function(obj)
{

    with(obj) 
    {
       alert(someObj);
    }
 }
 alert(typeof someObj);


 x ( {someObj:"yea"}) ;

 alert(typeof someObj);

1
这个 with 块唯一的好处就是你不必写 alert(obj.someObj),代价是增加了三行代码。 - Tom Lokhorst
1
"with" 是一个不好使用的东西。请参见 http://www.yuiblog.com/blog/2006/04/11/with-statement-considered-harmful/ 和 https://developer.mozilla.org/En/Core_JavaScript_1.5_Guide/Object_Manipulation_Statements。 - Jason S
1
等一下:「alert(someObj)」代码是哪里来的?你是自己编写的还是自动生成的代码?为什么不能使用「alert(obj.someObj)」? - Jason S
警告的内容将在函数之外,并且将引用应该传递给函数的本地范围中的某些内容...真的很难告诉你为什么是这样的:)) 真的 :) - Paweł Witkowski Photography
with 不会将变量注入到本地作用域中,它会创建一个新的作用域并将其推送到堆栈上。只有 varlet 可以将变量插入到当前作用域中。 - Hello71
显示剩余2条评论

1
你可以尝试使用命名参数技巧
编辑:这不是跨浏览器的
function x( {sex:sex, height:height} ) {
    alert( sex );
    alert( height );
}

x( { sex: 'male', height: 'short' } );
x( { height: 'medium', sex: 'female' } );

// male
// short
// female
// medium

有趣的是,这是ECMAScript还是特定的方言?(例如Spidermonkey,因为它似乎可以与Spidermonkey 1.7一起使用) - Jason S
有趣的一件事.. 我加上 +1 :) - Paweł Witkowski Photography
这是JS1.7的一部分,被称为解构赋值。您可以将此函数声明简化为:function x({sex,height}){...}。 - Prestaul
解构赋值的文档在解构赋值。不幸的是,它不是ECMA 5的一部分,但它在harmony proposals中,所以它可能会在未来出现。 - studgeek
这并没有解决OP的问题,因为他们同样可以做function x(sex, height)并适当地调用它... - xixixao

1

不确定您确切需要什么,但这是我的建议。

在现有函数中动态创建变量的唯一方法是通过您已经提到的eval方法。

另一个选项(由其他人提到)是让您的函数使用上下文映射,并且模板使用点符号表示法访问它(context.var1)

我最后的建议是使用Function构造函数,但我有一种感觉,这可能是您正在寻找的内容。(请注意,Function构造函数遇到与eval调用相同的问题)

var arg1 = "first";
var arg2 = "last";

// This is the body of the function that you want to execute with first
// and last as local variables. It would come from your template
var functionBody = "alert(first + ' ' + last)";

var myCustomFun = new Function(arg1, arg2,  functionBody);

myCustomFun("Mark", "Brown"); // brings up and alert saying "Mark Brown";

希望对你有所帮助


0

有趣的问题,从未想过这样的事情。但是使用案例是什么?

你想要做这样的事情的原因是,如果你不知道变量的名称。但是在这种情况下,再次访问变量的唯一方法是使用相同的引用对象。也就是说,你可以使用任何旧对象来存储数据。

从这样的引用对象中读取将会对调试很有帮助,但我不明白为什么你想要写入它。

编辑:

你发布的示例并没有让我相信需要访问局部作用域,因为你仍然在警报中硬编码了名称sex。这可以实现为:

function x(arg)
{
  container = {};
  container[arg.name] = arg.value;
  alert(container.sex);
}

你能详细说明一下这个例子吗?


这个示例并不是为了证明这是必要的。我正在开发一个模板系统,并解释为什么需要会花费很多时间,而且非常复杂 :) - Paweł Witkowski Photography
我只需要能够调用(alert(sex)),其中变量名可以从外部来源获取;) - Paweł Witkowski Photography
啊,所以问题就在于你的模板系统不允许在警告框中使用点号?;-) 否则,alert(obj.someObj) 就可以正常工作了。 - Tom Lokhorst
它允许使用点号...但我正在尝试替换一些过去的糟糕模板系统,我需要支持您可以在任何想要获取该模板的本地作用域中放置变量。 - Paweł Witkowski Photography

-1

我不太确定我理解你的问题。当创建一个类x时,我通常会这样做:

function x(args) {
  var _self = this;

  _self.PriviledgedMethod(a) {
      // some code
  }

  function privateMethod(a) {
      // some code
  }
}

var newObject = new x(args);

由于它被包含的函数封闭,因此您可以继续访问_self和args。


尽可能避免使用eval(有时您无法避免)。通过避免使用它,您将为更好的代码压缩提供可能性。 - Jacob Lauzier
我要求完全不同的东西 - 如何在本地范围内动态创建变量 - 这样您就可以键入alert(sex),其中'sex'是在本地范围内动态创建的。 - Paweł Witkowski Photography

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接