【问题标题】:Convert string in dot notation to get the object reference [duplicate]以点表示法转换字符串以获取对象引用[重复]
【发布时间】:2012-06-11 16:13:14
【问题描述】:

在 javascript 中考虑这个对象,

var obj = { a : { b: 1, c: 2 } };

给定字符串“obj.a.b”我怎样才能得到这个引用的对象,以便我可以改变它的值?即我希望能够做类似的事情

obj.a.b = 5;
obj.a.c = 10;

其中 "obj.a.b" 和 "obj.a.c" 是字符串(不是 obj 引用)。 我遇到了this post,在那里我可以获得点符号字符串引用 obj 的值,但我需要的是一种可以获取对象本身的方法?

对象的嵌套可能比这更深。即也许

var obj = { a: { b: 1, c : { d : 3, e : 4}, f: 5 } }

【问题讨论】:

    标签: javascript object syntax


    【解决方案1】:

    下面是dict 的简单类包装器:

    class Dots(dict):
        def __init__(self, *args, **kargs):
                super(Dots, self).__init__(*args, **kargs)
    
        def __getitem__(self, key):
                try:
                        item = super(Dots, self).__getitem__(key)
                except KeyError:
                        item = Dots()
                        self.__setitem__(key, item)
    
                return Dots(item) if type(item) == dict else item
    
        def __setitem__(self, key, value):
                if type(value) == dict: value = Dots(value)
                super(Dots, self).__setitem__(key, value)
    
        __getattr__ = __getitem__
        __setattr__ = __setitem__
    

    例子:

    >>> a = Dots()
    >>> a.b.c = 123
    >>> a.b.c
    123
    >>> a.b
    {'c': 123}
    >>> a
    {'b': {'c': 123}}
    

    缺失的密钥会即时创建为空Dots()

    >>> if a.Missing: print "Exists"
    ...
    >>> a
    {'Missing': {}, 'b': {'c': 123}}
    

    【讨论】:

      【解决方案2】:

      在 javascript 中无法返回对对象成员的可分配引用。您可以像这样使用单行代码通过点符号为深层对象成员赋值。

      new Function('_', 'val', '_.' + path + ' = val')(obj, value);
      

      在你的情况下:

      var obj = { a : { b: 1, c: 2 } };
      
      new Function('_', 'val', '_.a.b' + ' = val')(obj, 5); // Now obj.a.b will be equal to 5
      

      【讨论】:

        【解决方案3】:

        类似于 thg435 的答案,但带有参数检查并支持其中一个祖先级别尚未定义或不是对象的嵌套级别。

        setObjByString = function(obj, str, val) {
            var keys, key;
            //make sure str is a string with length
            if (!str || !str.length || Object.prototype.toString.call(str) !== "[object String]") {
                return false;
            }
            if (obj !== Object(obj)) {
                //if it's not an object, make it one
                obj = {};
            }
            keys = str.split(".");
            while (keys.length > 1) {
                key = keys.shift();
                if (obj !== Object(obj)) {
                    //if it's not an object, make it one
                    obj = {};
                }
                if (!(key in obj)) {
                    //if obj doesn't contain the key, add it and set it to an empty object
                    obj[key] = {};
                }
                obj = obj[key];
            }
            return obj[keys[0]] = val;
        };
        

        用法:

        var obj;
        setObjByString(obj, "a.b.c.d.e.f", "hello");
        

        【讨论】:

        • 如果你能想出一种方法来编写未定义的属性,而不覆盖同级预定义的属性,那就太好了
        【解决方案4】:

        要获得该值,请考虑:

        function ref(obj, str) {
            str = str.split(".");
            for (var i = 0; i < str.length; i++)
                obj = obj[str[i]];
            return obj;
        }
        
        var obj = { a: { b: 1, c : { d : 3, e : 4}, f: 5 } }
        str = 'a.c.d'
        ref(obj, str) // 3
        

        或者以更奇特的方式,使用reduce

        function ref(obj, str) {
            return str.split(".").reduce(function(o, x) { return o[x] }, obj);
        }
        

        在 javascript 中无法返回对对象成员的可分配引用,您必须使用如下函数:

        function set(obj, str, val) {
            str = str.split(".");
            while (str.length > 1)
                obj = obj[str.shift()];
            return obj[str.shift()] = val;
        }
        
        var obj = { a: { b: 1, c : { d : 3, e : 4}, f: 5 } }
        str = 'a.c.d'
        set(obj, str, 99)
        console.log(obj.a.c.d) // 99
        

        或使用上面给出的ref 来获取对包含对象的引用,然后对其应用[] 运算符:

        parts = str.split(/\.(?=[^.]+$)/)  // Split "foo.bar.baz" into ["foo.bar", "baz"]
        ref(obj, parts[0])[parts[1]] = 99
        

        【讨论】:

        • 谢谢第二部分是我一直在寻找的,似乎工作正常。
        • +1 起初没有看到您的 reduce 示例。
        • 如果您能详细说明 set()split(/\.(?=[^.]+$)/) 示例,我将不胜感激。
        • @Redsandro:嗯,你有什么问题吗?代码对我来说看起来很简单。
        • 现在很清楚了。我很困惑,因为在set() 中,您使用了与第一个ref() 不同的“数组遍历技术”,我试图弄清楚为什么这是必要的——它不是,但它让事情变得有趣。至于最后一个,正则表达式让我感到困惑,但我在代码中添加了注释。
        【解决方案5】:
        var obj = { a : { b: 1, c: 2 } };
        walkObject(obj,"a.b"); // 1
        
        function walkObject( obj, path ){
          var parts = path.split("."), i=0, part;
          while (obj && (part=parts[i++])) obj=obj[part];
          return obj;
        }
        

        或者,如果您喜欢简洁的代码:

        function walkObject( o, path ){
          for (var a,p=path.split('.'),i=0; o&&(a=p[i++]); o=o[a]);
          return o;
        }
        

        【讨论】:

        • 这不是让我得到点符号字符串的值吗?而不是我可以修改的对象本身?
        • @source.rar 这将返回位于链末尾的值,如第二行所示。如果该值是一个对象,那么您将返回一个对象(例如walkObject(obj,'a') // {b:1,c:2})。
        【解决方案6】:

        如果javascript 在浏览器中运行,那么您可以像这样访问该对象:

        window['obj']['a']['b'] = 5
        

        因此,给定字符串"obj.a.b",您必须将其拆分为.

        var s = "obj.a.b"
        var e = s.split(".")
        window[e[0]][e[1]][e[2]] = 5
        

        【讨论】:

        • 如果它有更多的嵌套级别怎么办?
        • 嵌套层数未知吗?
        • 是的。如果不知道有什么办法可以修改呢?
        猜你喜欢
        • 2011-09-17
        • 1970-01-01
        • 1970-01-01
        • 2016-09-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多