JS:将字符串“foo[bar]”转换为代码 obj.foo.bar 的简单方法

JS: easy way to convert string "foo[bar]" into code obj.foo.bar?

本文关键字:bar foo 代码 obj 方法 简单 转换 字符串 JS      更新时间:2023-09-26

我有一个变量obj定义如下:

{user: {username: "AzureDiamond", password: "hunter2"}}

我有一个字符串str可能定义为以下任何字符串:

  • "用户"
  • "用户[用户名]"
  • "用户[密码]"
  • "假的"

在JS(特别是node.js)中,是否有一种相对简单的方法来本质上/动态地执行以下操作?

  • str == "user"时,返回{username: "AzureDiamon", password: "hunter2"}
  • str == "user[username]"时,返回"AzureDiamond"
  • str == "user[password]"时,返回"猎人2"
  • str == "fake"时,返回null

编辑:这个问题更多的是找出是否有更简单或内置到 JS/node 中.js除了正则表达式匹配之外,我可以使用

解决方案

如果您确定 str 的语法正确,则该函数可能如下所示:

function get_by_path(source, path){
    var path_elements = path.split(']').join('').split('[');
    for (var i=0; i < path_elements.length; i++){
        source = source[path_elements[i]];
        if (typeof source === 'undefined'){
            return null;
        }
    };
    return source;
};

测试

这是它的行为方式:

var data = {'user': {
    'username': "AzureDiamond", 'password': "hunter2",
    'details': {'address': {'street': "Happiness Street"}}
}};
get_by_path(data, 'user');                           // gives user object
get_by_path(data, 'user[username]');                 // gives "hunter2"
get_by_path(data, 'user[password]');                 // gives "AzureDiamond"
get_by_path(data, 'fake');                           // gives null
get_by_path(data, 'user[details][address][street]'); // gives "Happiness Street"

解释

该脚本不使用正则表达式,也不使用危险的eval()调用,仅假设您的"路径"将从一个不带括号的单词开头,并且接下来的每一部分(如果有)都将用方括号括起来。如果在遍历的对象中找不到某些路径,则将返回null。如果它会被找到,它将被返回(无论它是一些复杂的对象、字符串、null、布尔值还是其他任何东西)。

脚本从解析路径开始。它通过删除右方括号("]")并通过左方括号("[")拆分结果字符串来实现这一点。该过程如下所示:

"user"                  -> "user"                -> ["user"]
"user[username]"        -> "user[username"       -> ["user", "username"]
"user[password]"        -> "user[password"       -> ["user", "password"]
"user[address][street]" -> "user[address[street" -> ["user", "address", "street"]
"fake"                  -> "fake"                -> ["fake"]

所以,如你所见,最后你有一个路径元素数组。这些是逐一评估的。如果在任何级别上无法对数据参数的结构进行更深入的适当步骤,则返回null。否则,将返回上次访问的元素。

证明

证明它有效的证据在这里:http://jsfiddle.net/EJCgE/2/

编辑:更复杂的路径(当有两个以上的级别时)存在一些问题,这是由于字符串的replace()方法的工作方式造成的。我已经更新了我的代码,不包括jQuery并解决了这个问题。

编辑2:我已经更新了脚本以删除多余的行和一个冗余变量。

这是直接从 EXTJS3 源代码中获取的,但我多次使用它来做类似的事情。

createAccessor : function(){
    var re = /['['.]/;
    return function(expr) {
        if(Ext.isEmpty(expr)){
            return Ext.emptyFn;
        }
        if(Ext.isFunction(expr)){
            return expr;
        }
        var i = String(expr).search(re);
        if(i >= 0){
            return new Function('obj', 'return obj' + (i > 0 ? '.' : '') + expr);
        }
        return function(obj){
            return obj[expr];
        };
    };
}(),

你会这样使用它:

var accessor = createAccessor(str);
var data = accessor(object);

尝试eval函数。 它接受一个字符串,并像执行javascript代码一样执行该字符串。 例如:

var data = {user: {username: "AzureDiamond", password: "hunter2"}};
var str = "user['"password'"]";
console.log( eval("data." + str) );
// Prints "hunter2"

不过,您必须非常小心,因为根据str的来源,人们基本上可以在您的服务器上远程运行代码。 在执行之前使用正则表达式验证字符串,以确保人们不会向您发送偷偷摸摸的信息并将您的服务器破解为位。

编辑:请注意,您还必须引用password,以便在执行时将其视为字符串,而不是变量。