3

如果我有这样的对象...

var rooter = {
    name: 'Billy',
    lastName: 'Moon',
    height: '1.4m'
}

我可以从这样的变量中访问属性...

var name = "name"
console.log(rooter[name])

var arb = "height"
console.log(rooter[arb])

快乐的时光!

但是,如果我有一个嵌套更深的对象,并且我想获得一个由字符串中的地址描述的叶子......

var rooter = {
    user: {
        firstName: 'Billy',
        lastName: 'Moon',
        arbitrary: {
            namespace: {
                height: '1.4m'
            }
        }
    }
}


var name = "user.lastName"
console.log(rooter[name]) // does not work

var arb = "user.arbitrary.namespace.height"
console.log(rooter[arb]) // does not work

没有骰子 :(

如何从描述路径的字符串中访问任意对象叶子?

编辑:找到带下划线的方法...

_.reduce(arb.split('.'), function(m, n){ return m[n] }, rooter)

对于 IE 9 及更高版本...

arb.split('.').reduce(function(m, n){ return m[n] }, rooter)
4

4 回答 4

1

我环顾四周,发现: Access object child properties using a dot notation string 这似乎是您问题的答案。

有几种方法可以访问对象中的不同后代。例如,您可以执行 rooter['name']['arbitrary']['namespace']['height'],以获得高度的值。但这似乎不是您想要的。

在那篇文章中,答案最终是您将编写自己的方法来执行此操作,在该方法中,您将接收一个字符串,用点分隔并将其拆分。然后你会找到那个元素并返回对象。

于 2013-09-24T14:51:44.317 回答
1

您可以使用eval(这通常是一个坏主意):

eval('rooter.' + name);

这样做的更好方法可能是:

function namespace(namespaceString) {
    var parts = namespaceString.split('.'),
        parent = window,
        currentPart = '';    

    for(var i = 0, length = parts.length; i < length; i++) {
        currentPart = parts[i];
        parent[currentPart] = parent[currentPart] || {};
        parent = parent[currentPart];
    }

    return parent;
}

console.log(namespace('rooter.user.firstName'));
于 2013-09-24T14:31:40.963 回答
0

递归方法(来自这个问题

var rooter = { user: { firstName: 'Billy', lastName: 'Moon', arbitrary: { namespace: { height: '1.4m' } } } };

var arb = "user.arbitrary.namespace.height";

fromPathString = function(pathString, targetObject){
    pathString = pathString.split('.');
    for(var i = 0; i < pathString.length; i++){
        targetObject = (targetObject[pathString[i]])? targetObject[pathString[i]] : targetObject[pathString[i]] = {};
    };
    return targetObject
}

console.log(fromPathString(arb, rooter))

减少方法

arb.split('.').reduce(function(m, n){ return m[n] }, rooter)

因为.reduce不是所有浏览器都兼容...

Feature Chrome  Firefox (Gecko) Internet Explorer   Opera   Safari
Basic support   (Yes)   3.0 (1.9)   9   10.5    4.0

用于 IE 9 及以下版本的 Shim...(来自 MDN

只需在调用.reduce任何数组之前放置...

if ('function' !== typeof Array.prototype.reduce) {
  Array.prototype.reduce = function(callback, opt_initialValue){
    'use strict';
    if (null === this || 'undefined' === typeof this) {
      // At the moment all modern browsers, that support strict mode, have
      // native implementation of Array.prototype.reduce. For instance, IE8
      // does not support strict mode, so this check is actually useless.
      throw new TypeError(
          'Array.prototype.reduce called on null or undefined');
    }
    if ('function' !== typeof callback) {
      throw new TypeError(callback + ' is not a function');
    }
    var index, value,
        length = this.length >>> 0,
        isValueSet = false;
    if (1 < arguments.length) {
      value = opt_initialValue;
      isValueSet = true;
    }
    for (index = 0; length > index; ++index) {
      if (this.hasOwnProperty(index)) {
        if (isValueSet) {
          value = callback(value, this[index], index, this);
        }
        else {
          value = this[index];
          isValueSet = true;
        }
      }
    }
    if (!isValueSet) {
      throw new TypeError('Reduce of empty array with no initial value');
    }
    return value;
  };
}
于 2013-09-24T14:46:55.893 回答
0

签出此代码:

function access(obj, prop, defVal) {
    var objectNames = prop.split(".");

    var curObj = obj;

    for (var i = 0, len = objectNames.length; i < len; i++) {
        curObj = curObj[objectNames[i]];
        if (typeof curObj === 'undefined') {
            return defVal;
        }
    }
    return curObj;
}

jsFiddle

于 2013-09-24T14:32:42.700 回答