【问题标题】:Use dynamic variable names in JavaScript在 JavaScript 中使用动态变量名
【发布时间】:2011-07-04 06:42:36
【问题描述】:

在 PHP 中,你可以做如下惊人/可怕的事情:

$a = 1;
$b = 2;
$c = 3;
$name = 'a';
echo $$name;
// prints 1

有没有办法用 Javascript 做这样的事情?

例如如果我有一个var name = 'the name of the variable';,我可以得到一个名为name 的变量的引用吗?

【问题讨论】:

  • 这能回答你的问题吗? "Variable" variables in Javascript?。那里接受的答案比这里的更好,因为它显示了如何做到这一点,而且正确地警告说,几乎总是有更好的方法来做你想做的任何事情。请参阅元数据上的XY problem

标签: javascript dynamic-variables


【解决方案1】:

由于 ECMA-/Javascript 都是关于 ObjectsContexts(它们也是某种对象),因此每个变量都存储在一个名为 Variable- 的一个函数,激活对象)。

所以如果你像这样创建变量:

var a = 1,
    b = 2,
    c = 3;

全局范围(=无函数上下文)中,您将这些变量隐式写入全局对象(=浏览器中的window)。

这些可以通过使用“点”或“括号”符号来访问:

var name = window.a;

var name = window['a'];

这仅适用于此特定实例中的全局对象,因为 全局对象变量对象window 对象本身。在函数的上下文中,您无法直接访问激活对象。例如:

function foobar() {
   this.a = 1;
   this.b = 2;

   var name = window['a']; // === undefined
   alert(name);
   name = this['a']; // === 1
   alert(name);
}

new foobar();

new 创建一个自定义对象(上下文)的新实例。如果没有new,函数的作用域也是global (=window)。此示例将分别提醒undefined1。如果我们将this.a = 1; this.b = 2 替换为:

var a = 1,
    b = 2;

两个警报输出都未定义。在这种情况下,变量ab 将存储在来自foobar 的激活对象中,我们无法访问(当然我们可以通过调用ab 直接访问它们)。

【讨论】:

  • 另一个很酷的事情是,通过这种方式,您可以为任何全局级别的函数添加回调(开始/结束)。
  • 但是如果我的动态变量在函数中是局部的呢?例如:函数 boink() { var a = 1; // 这不起作用 var dynamic = this['a']; // 这也不行 var dynamic = ['a']; }
  • @Kokodoko——因为 this 不是“上下文”或对函数执行上下文的引用(无法引用执行上下文,ECMA 禁止这样做-262)。 this 由函数的调用方式(或通过 bind)设置,它只是一个对象,与可访问的执行上下文无关。
  • 如果您需要访问嵌套属性,请查看stackoverflow.com/questions/4244896/…
  • 用括号符号为我指明了正确的方向。只考虑点符号。
【解决方案2】:

eval 是一种选择。

var a = 1;
var name = 'a';

document.write(eval(name)); // 1

警告:请注意,如果您不知道自己在做什么,不建议使用eval() 函数,因为它会带来多个安全问题。除非绝对必要,否则请使用其他东西。请参阅the MDN page for eval 了解更多信息。

【讨论】:

  • 不应该,因为 eval 是邪恶的。永远不要使用 eval!
  • @EasyBB - 如果您要说永远不要使用某些东西,我无助于解释原因。我有一种情况,除了 eval() 之外,我想不出任何其他方法来完成我正在做的事情
  • Eval 存在攻击最终用户的风险,我们认为它在技术上并不是邪恶的,而是在丢失的案例中被误解和误用。我已经看到 php 响应在其中包含文字变量,然后使用 eval 运行它。尽管在这种情况下不应该使用它,因为有更好的方法。根本不应该使用这个问题 eval ,因为总体上有更好的方法,我相信我们很多人都知道这一点。
  • Via javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval --- “让我们考虑一下最常反对使用 eval 的论点:1) 它需要编译,因此速度很慢 2) 如果恶意脚本进入 eval 怎么办参数?3)它看起来很难看 4)它继承了执行上下文和它被调用的范围的 this 绑定”
  • 这里是如何使用 eval 创建动态变量:stackoverflow.com/a/13291766/5528600
【解决方案3】:

您可以使用窗口对象来获取它。

window['myVar']

window 引用了您正在使用的所有全局变量和全局函数。

【讨论】:

  • 不用说,这个比 eval() 更安全。
  • window 看起来像 state。这真的很有帮助。
【解决方案4】:

只是不知道一个糟糕的答案得到这么多票。答案很简单,但你把它弄复杂了。

// If you want to get article_count
// var article_count = 1000;
var type = 'article';
this[type+'_count'] = 1000;  // in a function we use "this";
alert(article_count);

【讨论】:

  • "在一个函数中我们使用this" - 如果你想以这种方式访问​​一个全局变量,最好是明确的并使用window对象,而不是 thisthis 不明确。
  • 但是在函数内部你不能使用this或其他任何东西来访问你的例子中的变量type,如果你在另一个变量中有它的名字:function test(vname) { var type = 'article'; this[vname] = 'something else'; alert(type); }; test('type') 将显示 article,而不是 something else。这就是“复杂答案”所解释的。
  • 这不起作用。如果您将undefined 放入函数中并使用对象(使用new 运算符或使用点符号)调用它,它会将undefined 输出到警报框。
  • 在 Express.js 路由中效果很好
  • 感谢@Terry,这在 Vue 中完美运行。当您声明了多个数据属性,并且您想要一个方法来决定要定位哪个数据属性时,您只需像这样传递属性名称:changeProperty(propertyName) { this[propertyName] = 1; } changeProperty("bar")changeProperty("baz")
【解决方案5】:

这是一个例子:

for(var i=0; i<=3; i++) {
    window['p'+i] = "hello " + i;
}

alert(p0); // hello 0
alert(p1); // hello 1
alert(p2); // hello 2
alert(p3); // hello 3

另一个例子:

var myVariable = 'coco';
window[myVariable] = 'riko';

alert(coco); // display : riko

所以,myVariable的值“coco”变成了一个变量coco

因为全局范围内的所有变量都是 Window 对象的属性。

【讨论】:

    【解决方案6】:
    a = 'varname';
    str = a+' = '+'123';
    eval(str)
    alert(varname);
    

    试试这个...

    【讨论】:

      【解决方案7】:

      在 Javascript 中,您可以使用所有属性都是键值对这一事实。 jAndy 已经提到了这一点,但我不认为他的回答表明它可以被利用。

      通常您不会尝试创建一个变量来保存变量名称,而是尝试生成变量名称然后使用它们。 PHP 使用 $$var 符号来实现,但 Javascript 不需要这样做,因为属性键可以与数组键互换。

      var id = "abc";
      var mine = {};
      mine[id] = 123;
      console.log(mine.abc);
      

      给出 123。通常你想构造变量,这就是为什么会有间接性,所以你也可以反过来做。

      var mine = {};
      mine.abc = 123;
      console.log(mine["a"+"bc"]);
      

      【讨论】:

      • var someJsonObj = {};在一个循环中...... for(var i=0; i
      【解决方案8】:

      如果你不想使用像窗口或全局(节点)这样的全局对象,你可以试试这样的:

      var obj = {};
      obj['whatever'] = 'There\'s no need to store even more stuff in a global object.';
      
      console.log(obj['whatever']);
      

      【讨论】:

        【解决方案9】:

        2019

        TL;DR

        • eval 运算符可以在它调用的上下文中运行字符串表达式并从该上下文返回变量;
        • literal object 理论上可以通过 write:{[varName]} 做到这一点,但它被定义阻止了。

        所以我遇到了这个问题,这里的每个人都只是在玩,没有带来真正的解决方案。但是@Axel Heider 有一个很好的方法。

        解决方案是eval。 几乎被遗忘的运营商。 (认为​​最多的是with()

        eval 运算符可以在它调用的上下文中动态运行表达式。并返回该表达式的结果。我们可以使用它在函数的上下文中动态返回变量的值。

        示例:

        function exmaple1(){
           var a = 1, b = 2, default = 3;
           var name = 'a';
           return eval(name)
        }
        
        example1() // return 1
        
        
        function example2(option){
          var a = 1, b = 2, defaultValue = 3;
        
          switch(option){
            case 'a': name = 'a'; break;
            case 'b': name = 'b'; break;
            default: name = 'defaultValue';
          }
          return eval (name);
        }
        
        example2('a') // return 1
        example2('b') // return 2
        example2() // return 3
        

        请注意,我总是明确地写出表达式eval 将运行。 避免代码中出现不必要的意外。 eval很强大 但我相信你已经知道了

        顺便说一句,如果它是合法的,我们可以使用literal object 来捕获变量名称和值,但是我们不能将计算的属性名称和属性值组合起来,遗憾的是,它是无效的

        functopn example( varName ){
            var var1 = 'foo', var2 ='bar'
        
            var capture = {[varName]}
        
        }
        
        example('var1') //trow 'Uncaught SyntaxError: Unexpected token }`
        

        【讨论】:

        • 这是一个快速的解决方案,但这是一个不好的做法,因为它不安全并且由于 JS 引擎无法优化该方法而降低性能。
        • 很棒的解决方案
        • "default" 是 JavaScript 中的保留字。您不应该将其用作变量名
        【解决方案10】:

        我需要动态绘制多个 FormData,并且对象方式效果很好

        var forms = {}
        

        然后在我的循环中,无论我需要创建我使用的表单数据

        forms["formdata"+counter]=new FormData();
        forms["formdata"+counter].append(var_name, var_value);
        

        【讨论】:

        • 谢谢...它完全救了我! this.$refs['listView' + index].nativeView.animate({..}) 我需要像 this.$refs.listView1 listView2 这样的 refs 内的变量...
        【解决方案11】:

        对于那些需要导出动态命名变量的人来说,这是一种替代方法

        export {
          [someVariable]: 'some value',
          [anotherVariable]: 'another value',
        }
        
        // then.... import from another file like this:
        import * as vars from './some-file'
        

        另一种选择是简单地创建一个对象,其键是动态命名的

        const vars = { [someVariable]: 1, [otherVariable]: 2 };
        
        // consume it like this
        vars[someVariable];
        

        【讨论】:

        • 为什么需要import/export 来做这件事?为什么不简单地创建一个对象并访问它的属性呢?此外,不可能导出动态名称,除非您将对象导出为默认值...
        【解决方案12】:

        使用对象也很棒。

        var a=123
        var b=234
        var temp = {"a":a,"b":b}
        console.log(temp["a"],temp["b"]);
        

        【讨论】:

          【解决方案13】:

          虽然这有一个公认的答案,但我想补充一点:

          在 ES6 中使用 let 不起作用

          /*this is NOT working*/
          let t = "skyBlue",
              m = "gold",
              b = "tomato";
          
          let color = window["b"];
          console.log(color);

          但是使用var 有效

          /*this IS working*/
          var t = "skyBlue",
              m = "gold",
              b = "tomato";
          
          let color = window["b"];
          console.log(color);

          我希望这对某些人有用。

          【讨论】:

          • 同样适用于const
          • 是的。但是您可以使用变量创建一个对象并从那里选择变量:const vars = { t, m, b }; console.log(vars['b'])。否则eval 也可以。
          • @FabianvonEllerts 您发表评论的目的是什么?此答案仅旨在解决块级范围(letconst)和全局(window)范围(varfunction)之间的区别。您的评论与此无关,而是作为单独的答案。
          【解决方案14】:

          他们的意思是不,你不能。 没有办法完成它。 所以你可以做这样的事情

          function create(obj, const){
          // where obj is an object and const is a variable name
          function const () {}
          
          const.prototype.myProperty = property_value;
          // .. more prototype
          
          return new const();
          
          }
          

          拥有一个创建函数,就像在 ECMAScript 5 中实现的那样。

          【讨论】:

          • 注意:const 是 ES6 中的关键字
          • ...在此之前是一个未来的保留字
          • eval运营商
          【解决方案15】:

          eval() 在我的测试中不起作用。但是向 DOM 树中添加新的 JavaScript 代码是可能的。所以这是一个添加新变量的函数:

          function createVariable(varName,varContent)
          {
            var scriptStr = "var "+varName+"= \""+varContent+"\""
          
            var node_scriptCode = document.createTextNode( scriptStr )
            var node_script = document.createElement("script");
            node_script.type = "text/javascript"
            node_script.appendChild(node_scriptCode);
          
            var node_head = document.getElementsByTagName("head")[0]
            node_head.appendChild(node_script);
          }
          
          createVariable("dynamicVar", "some content")
          console.log(dynamicVar)
          

          【讨论】:

          • 小改进,最好用var node_head = document.getElementsByTagName("head")[0]而不是ID,因为没人给id="head"&lt;head&gt; :-)
          • 我愿意 :) 但是谢谢,现在我终于可以删除这个 `id="head" 东西了
          • 这似乎是一种过于复杂的创建全局变量的方法?! (……这如何回答这个问题?)
          • 天才 :) eval 是解决方案。即使您的代码不起作用
          【解决方案16】:

          最好使用创建命名空间并在其中声明一个变量,而不是将其添加到全局对象中。我们还可以创建一个函数来获取和设置值

          见下面代码sn-p:

          //creating a namespace in which all the variables will be defined.
          var myObjects={};
          
          //function that will set the name property in the myObjects namespace
          function setName(val){
            myObjects.Name=val;
          }
          
          //function that will return the name property in the myObjects namespace
          function getName(){
            return myObjects.Name;
          }
          
          //now we can use it like:
            setName("kevin");
            var x = getName();
            var y = x;
            console.log(y)  //"kevin"
            var z = "y";
            console.log(z); //"y"
            console.log(eval(z)); //"kevin"
          

          以类似的方式,我们可以声明和使用多个变量。虽然这样会增加代码行,但是代码会更健壮,更不容易出错。

          【讨论】:

            【解决方案17】:

            这将完全按照您在 php 中所做的:

            var a = 1;
            var b = 2;
            var ccc = 3;
            var name = 'a';
            console.log( window[name] ); // 1
            

            【讨论】:

            • 使用全局范围 - 这是个坏主意,恕我直言
            猜你喜欢
            • 2011-05-12
            • 1970-01-01
            • 2011-09-30
            • 2019-06-08
            • 2019-12-23
            • 2013-03-25
            相关资源
            最近更新 更多