按字符串值引用javascript对象 - 不使用eval()

时间:2014-01-29 18:37:18

标签: javascript eval

环顾四周,没有找到任何与我想做的事情相符的事情。

我试图通过字符串表示来引用一个对象,虽然我看到的每个地方都看到使用eval()很糟糕 - 虽然在没有使用eval()的情况下无法找到方法

所以我的用例:

我在按钮上有数据属性;

data-original-data-object="window.app.myData.originalData"

单击该按钮时,我需要访问window.app.myData.originalData

处的实际对象

现在,我知道我能做到:

var dataObj = eval($(this).data('original-data-object'));

虽然还有其他办法吗?

如果有帮助,window.app.myData.originalData存储的数据就是JSON对象。

4 个答案:

答案 0 :(得分:3)

像这样:

var obj = (function(str){
  var arr = str.split('.');

  if (arr[0] === 'window'){
    arr.shift();
  }

  return arr.reduce(function(a, b){
     return a[b];
  }, window);

}("window.app.myData.originalData"))

答案 1 :(得分:1)

我想到了几个解决方案。第一个解决方案在@CD答案中暗示。第二种是通过正则表达式将该字符串限制为只是属性名称,这样您就可以安全地使用eval。

遍历window对象以获取值(无eval)

function getValue(s) {
    var keys = s.split("."), o = window, key, i, length, undef;

    if (keys[0] === "window") {
        keys.shift();
    }

    for (i = 0, length = keys.length; i < length; i++) {
        key = keys[i];

        if (!(key in o) || o[key] === null || o[key] === undef) {
            throw new Error("Could not get value of " + s);
        }

        o = o[key];
    }

    return o;
}

将字符串限制为有效的属性名称:

function getValue(s) {
    var regex = /^[\w$][\w.]+$/, value;

    if (regex.test(s)) {
        try {
            value = eval(s);
        }
        catch (error) {
            throw new Error("Could not get value of " + s + " (" + error.message + ")");
        }
    }
    else {
        throw new Error("Could not get value of " + s);
    }

    return value;
}

使用:

var x = getValue(this.getAttribute("data-original-data-object"));

您希望避免使用eval,因为它可以随意执行您可能或可能无法控制的JavaScript。在这种特殊情况下,您知道所需的确切字符串类型。在我看来,我使用正则表达式来确保字符串只包含由点分隔的属性名称。说到安全性,这两行代码没有区别:

var x = eval("window.foo");
var x = window.foo;

答案 2 :(得分:0)

如果您可以确保无论如何都不能修改属性,这可能会对正在实施的网站/项目造成损害,我认为没有任何问题。

答案 3 :(得分:0)

我不确定这是否适用于您的情况,但是避免使用eval的简单解决方案可能是添加“window.app.myData.originalData”及其JSON数据作为将保留的对象的属性范围。

类似的东西:

var exampleData = { id:1, content:"..." };

var dataStore = { "window.app.myData.originalData": exampleData  };

然后,在您的点击处理程序中:

var retrievedData = dataStore[$(this).data('original-data-object')];    // uses "window.app.myData.originalData" to retrieve exampleData

在这种情况下,您需要使用括号表示法访问数据,因为。属性名称中的字符。但是,这种方法应该比尝试使用eval更快更安全。