如何在node.js中的当前作用域中动态动态创建变量?

时间:2017-09-27 05:21:38

标签: node.js

我正在尝试动态创建指向对象的node.js变量。

我知道我可以使用eval在范围内动态创建变量:

var vars = ['a','b']
for(var n=0; n<vars.length; n++) {
   eval('var '+vars[n]+' = '+n)
}

console.log(b) // prints 1

以上动态创建变量,并为它们提供vars列表中索引的值。

但是如果我想将这些动态变量设置为对象引用呢?如下所示:

var vars = {a: {}, b:{}}
for(var k in vars) {
   eval('var '+k) // create the variable dynamically
   new Function('value', k+' = value')(vars[k]) // attempt to set the value
}

a.b = 5
console.log(vars.a.b) // undefined : (

我知道上面的原因不起作用 - new Function创建的函数无法看到当前作用域,因此无法设置该值。有没有办法做我想做的事情,这样console.log(vars.a.b)会打印“5”而不是“未定义”?

更新:

嗯,我错了,new Function无法在本地范围内查看或修改变量,因为这样可行:

var obj = {}
eval('var x')
new Function('value', 'x = value')(obj)

obj.a = 5
console.log(x.a) // prints 5

所以现在我很困惑为什么我的循环似乎不起作用..

更新2:

我刚刚意识到我的代码实际上 在chrome的控制台中工作。但它不能在node.js中工作......

对PHIL的更新:

这是我的情况。我正在使用Parsimmon来构建解析器组合器。这就是这样做的:

var L = Parsimmon.createLanguage({
  combinator1: function() {
     return Parsimmon.string('hi')
  },
  combinator2: function() {
     return L.combinator1.many()
  }
}) 

我想在我编写的每个解析器组合器之前消除编写L.的需要。我能做到这一点:

var combinator2 = L.combinator2

但这需要我为我编写的每个组合器添加一条额外的行。正如您所看到的,我无法使用with,因为L是在我能够编写with(L)之后创建的,如果我在下面定义我的函数,那么在对象中使用它们,每次我写一个新的组合器时,我都会重复这些函数名称。

总而言之,我想循环遍历L并将所有生成的解析器组合器放入范围内的一个漂亮的干净变量中,这样我就可以编写combinator1而不是L.combinator1(等)。

2 个答案:

答案 0 :(得分:1)

IIUC,无论是否有更好的方法来实现您的目标,如果您只是删除动态'var '上的Function,它将在外部(全局)范围内运作。

变化:

new Function('value', k+' = value')(vars[k])

为:

new Function('value', k+' = value')(vars[k])

所以:

var vars = {a: {}, b:{}}
for(var k in vars) {
   eval('var '+k) // create the variable dynamically
   new Function('value', k+' = value')(vars[k]) // attempt to set the value
}

a.b = 5
console.log(vars.a.b)

您不希望在函数内声明具有局部作用域的新变量,您希望在外部作用域上操作。

更新以解决新问题

你的第一个循环确实有效。尝试对ab进行反省;它们应该是预期的,分别为0和1。

根据信息更新2,这适用于Node.js

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FunctionFunction始终适用于全局范围。在Node中,这是globalvar变量不是全局范围,而是模块的范围。要为Node修复此问题,您可以执行以下操作并省略eval var声明(该模块将覆盖您在Function内可访问的全局范围的模块):

var vars = {a: {}, b:{}}
for(var k in vars) {
   new Function('value', k +' = value')(vars[k]) // attempt to set the value
}

a.b = 5
console.log(vars.a.b) // 5

换句话说,内部函数设置自动变为可通过global访问的变量,因此您的模块代码在没有任何模块范围的var a声明覆盖全局,您可以使用行a设置全局a.b = 5属性。

更新3

由于我刚刚在理解Function时解决了您的问题,因此我提供了上述信息。根据您的后续评论(同样,在不说明其适用于您的特定用例的情况下),您可以通过eval操作对象,如下所示:

var vars = {a: {}, b:{}}
for(var k in vars) {
   eval('var '+k+' = vars["'+k+'"]')
}

a.b = 5
console.log(vars.a.b) // 5

但要重申其他人发出的警告 - 使用eval通常不是一个好主意,并且当引用的变量包含任意用户数据时可能会很危险......

答案 1 :(得分:0)

更改此行:

docker-py

因为在你的情况下a未定义为什么它现在允许创建新属性

vars.a将返回一个对象,而不仅仅是一个vars属性。