访问多个嵌套对象

时间:2018-06-17 17:46:22

标签: javascript angularjs square-bracket

我正在为我的应用程序制作全局数据存储(Angular JS应用程序 - 但这是一个关于JS的问题,特别是Angular的问题。)

我已设置service来设置数据,获取数据等。

看起来像这样:

angular.module('core').factory('dataService', function(callsService) {
  let properties = {
    globalData: {}
  };

  properties.insertData = function(data) {
    for (let x in data) {
      this.globalData[x] = data[x];
    }
    return;
  }

  properties.getData = function(data) {
    return this.globalData[data];
  }

  return properties;
});

使用该服务会是这样的:

dataService.insertData({foo: 'bar'});
dataService.getData('foo'); // 'bar'

但是当存在嵌套数据时会出现问题,如下所示:

dataService.insertData({foo: {bar: 'hello world'}});
dataService.getData('foo'); // {bar: 'hello world'}

这显然是对象引用如何工作,但我怎么能传递像:

dataService.getData('foo.bar'); // 'hello world'

dataService.getData('[foo][bar]'); // 'hello world'

回到我的properties.getData方法,是否有办法以递归方式(或其他方式)访问嵌套对象?

properties.getData = function(data) {
  return this.globalData[data]; // needs to be able to get nested objects
}

4 个答案:

答案 0 :(得分:2)

更新答案:

我认为这个递归的一个班轮将完全符合您的要求:

properties.getData = (args, data) => args.length ? this.getData(args.slice(1), data ? data[args[0]] : this.globalData[args[0]]) : data ? data : this.globalData

使用无限量的属性参数或数组中的数组索引来调用它,如下所示:

dataService.getData(['arrayOfData', 2, 'propOnArrElement', 'subProp', 'desiredValue'])

<强>解释

&#34;签名&#34;该函数的类似于

getData(args: Array, data?: any): any

表示:

  1. 它将一个数组作为第一个参数(包含您希望遍历以获取嵌套数据的属性/索引的跟踪)
  2. 它将我们查询的数据结构作为可选第二个参数(当然,这必然是一个Object或一个数组)
  3. 它将返回所需的数据,可以是任何类型的数据。
  4. 工作原理:

    调用该函数时,

    • 不应该定义第二个参数,以便服务可以到达globalData对象,我们将在后面看到。
    • 检查args数组的长度(args.length ?)和
      • 如果有元素,则进行递归调用(this.getData(),
        • 但是这一次,我们将从args数组中删除第一个arg(args.slice(1),),
        • 并且数据参数将被(重新)包括在内(data ?)。
          • 如果它是在最近的递归调用中定义的,那么第一个arg元素用于访问数据对象/数组(data[args[0]] :)上的属性(或索引),
          • 但是如果还没有定义(就像在初始函数调用中那样),递归调用将使用globalData属性(this.globalData[args[0]]))。
      • 随着函数继续它的递归过程,数据结构正在缩小到更深层次的数据,并且参数列表正在逐渐减少。
        • 一旦args长度解析为false(不再需要args进行探索!),而不是返回另一个递归调用,该函数只返回当前数据对象(: data ? data)。
        • 如果使用空数组调用此函数,则将返回整个globalData(: this.globalData)。

    我希望你能找到这个有用的,或者至少是愉快的阅读。今晚淋浴时,这个解决方案突然出现在我脑海里,我当然很兴奋。 :P

    奖励材料

    这是一种类似(甚至更好)的方法,使用ES6 rest参数和Array.reduce(这将允许你在不传递数组的情况下调用函数):

    properties.getData = (...args) => args.reduce((data, arg) => data[arg], this.globalData)
    
    像这样打电话:

    dataService.getData('firstarg', 'secondarg', 'onemorearg', 'desireddata')
    

    原创,不满意答案:

    由于您返回数据,您可以直接在函数调用上访问该属性:

    const nestedVal = dataService.getData(‘foo’).bar
    

    或者:

    const nestedVal = dataService.getData(‘foo’)[‘bar’]
    

答案 1 :(得分:1)

这似乎是两个问题之一。

回答您的第一个问题(传递dataService.getData('foo.bar');

之类的内容

您可以使用如下字符串访问对象属性:

var property = foo['bar'];

如果您愿意,可以进行递归,例如:

var property = foo['bar']['baz'];

关于您的第二个问题,这可能与this

重复

答案 2 :(得分:0)

如果我可能建议使用箭头功能作为选择器,例如:

dataService.getData(storage => storage.foo.bar);

您服务中的功能将是:

properties.getData = function (dataSelector) {
    return dataSelector(this.globalData);
} 

这是一个有效的例子:

&#13;
&#13;
const data = {
  prop1: {
    prop2: 1
  }
};

function getData(dataSelector) {
  return dataSelector(data);
}

const prop2 = getData(data => data.prop1.prop2);

console.log(prop2);
&#13;
&#13;
&#13;

否则你必须使用正则表达式来分割字符串,例如:

properties.getData = function(data) {  
  var props = data.replace(/\]/g,'').split(/\.\[/g);

 return props.reduce((obj, prop) => obj[prop], this.globalData);

} 

进一步参考this文章可能有用

答案 3 :(得分:0)

使用$parse服务:

  var object = { 'a': [{ 'b': { 'c': 3 } }] };
  var accessor= 'a[0].b.c';

  var result = $parse(accessor)(object);
  console.log("result =>",result);

  // result => 3 

DEMO

&#13;
&#13;
angular.module("app",[])
.run(function($parse) {

  var object = { 'a': [{ 'b': { 'c': 3 } }] };
  var accessor= 'a[0].b.c';
  
  var result = $parse(accessor)(object);
  console.log("result =>",result);
  
  // result => 3 
})
&#13;
 <script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
</body>
&#13;
&#13;
&#13;

有关详细信息,请参阅AngularJS $parse Service API Reference