在JavaScript中通过字符串名称设置变量?

3
//window["Fluent"]["Include"]

function setGlobalVariableByName(name,value)
{
    var indexes = name.split(".");
    var variable = null;
    $.each(indexes, function()
    {
        if (variable == null){
            variable = window[this];
        }else{
            variable = variable[this];
        }
    });

    variable = value;
}

setGlobalVariableByName("Fluent.Include.JqueryPulse",true);
console.log(Fluent.Include.JqueryPulse) // prints false

这显然行不通。如果我只想获取变量的值,那么它可以工作,但对于设置变量则不行。

window["Fluent"]["Include"]["JqueryPulse"] = true;
console.log(Fluent.Include.JqueryPulse) // prints true

如何在不使用eval的情况下实现这样的功能?
我需要一种方法来以编程方式向数组添加索引,我猜想


以下代码可以正常工作,您能否建议更好的编码方式以使其更加DRY?

function setGlobalVariableByName(name,value)
{
    var indices = name.split(".");
    var parent;
    $.each(indices, function(i)
    {
        if(i==indices.length-1){
            if (!parent){
                window[this] = value;
            }else{
                parent[this] = value;
            }
        }else if (!parent){
            parent = window[this];
        }else{
            parent = variable[this];
        }
    });
}

setGlobalVariableByName : function(name, value)
{
    var indices = name.split(".");
    var last = indices.pop();
    var parent;
    $.each(indices, function(i)
    {
        if (!parent){
            parent = window[this];
        }else{
            parent = variable[this];
        }
    }); 
    if (!parent){
        window[last] = value;
    }else{
        parent[last] = value;
    }
}

它们确实存在,我只是为了问题而这样解释。变量Fluent.Include.JqueryPulse已经存在,其值为false,我想将其设置为true。但我不需要初始化任何东西。 - bevacqua
这是另一个版本:http://jsfiddle.net/3WtJM/2/ - Brad Christie
@Nico - 你说,“变量Fluent.Include.JqueryPulse已经存在了……” 要小心,不要踩到已经存在于该链中的对象,否则将失去它们的属性。请查看我的答案和代码注释,以避免这个问题。 - JAAulde
2个回答

5
您需要调用
variable[this] = value 

不知何故。因此,在到达最后一个名称之前,您需要打破拆分字符串的循环,然后再赋值。

最终,您需要调用:

variable = window['Fluent']['Include']; // build this in a loop
variable['JqueryPulse'] = someValue; // then call this

0

最终,您只是在构建对象链并将链中的最后一项设置为值。此外,我会添加一个检查,以确保已经是对象的项目不会被覆盖,以便它们现有的属性不会丢失:

//bootstrap the object for demonstration purposes--not necessary to make code work
window.Fluent = {
  Include: {
    foo: 'bar', //don't want to lose this'
    JqueryPulse: false //want to set this to true
  }
};

//define function
function setGlobalItemByName( name, value )
{
  var names,
      finalName,
      //no need to figure out if this should be assigned in the loop--assign it now
      currentOp = window;

  if( typeof name === 'string' && name !== '' )
  {
    names = name.split( '.' );
    //no need to track where we are in the looping--just pull the last off and use it after
    finalName = names.pop();

    $.each( names, function()
    {
      //If the current item is not an object, make it so. If it is, just leave it alone and use it
      if( typeof currentOp[this] !== 'object' || currentOp[this] === null )
      {
        currentOp[this] = {};
      }

      //move the reference for the next iteration
      currentOp = currentOp[this];
    } );

    //object chain build complete, assign final value
    currentOp[finalName] = value;
  }
}

//use function
setGlobalItemByName( 'Fluent.Include.JqueryPulse', true );


//Check that Fluent.Include.foo did not get lost
console.log( Fluent.Include.foo );
//Check that Fluent.Include.JqueryPulse got set
console.log( Fluent.Include.JqueryPulse );

然而,即使您在页面上有jQuery可用,我也会不使用jQuery来完成它。没有必要为每个index执行一个函数的开销。

//bootstrap the object for demonstration purposes--not necessary to make code work
window.Fluent = {
  Include: {
    foo: 'bar', //don't want to lose this'
    JqueryPulse: false //want to set this to true
  }
};

//define function
function setGlobalItemByName( name, value )
{
  var names,
      finalName,
      indexCount,
      currentIndex,
      currentName,
      //no need to figure out if this should be assigned in the loop--assign it now
      currentOp = window;

  if( typeof name === 'string' && name !== '' )
  {
    names = name.split( '.' );
    //no need to track where we are in the looping--just pull the last off and use it after
    finalName = names.pop();

    indexCount = names.length;
    for( currentIndex = 0; currentIndex < indexCount; currentIndex += 1 )
    {
      currentName = names[currentIndex];

      //If the current item is not an object, make it so. If it is, just leave it alone and use it
      if( typeof currentOp[currentName] !== 'object' || currentOp[currentName] === null )
      {
        currentOp[currentName] = {};
      }

      //move the reference for the next iteration
      currentOp = currentOp[currentName];
    }

    //object chain build complete, assign final value
    currentOp[finalName] = value;
  }
}

//use function
setGlobalItemByName( 'Fluent.Include.JqueryPulse', true );


//Check that Fluent.Include.foo did not get lost
console.log( Fluent.Include.foo );
//Check that Fluent.Include.JqueryPulse got set
console.log( Fluent.Include.JqueryPulse );

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