下划线 - 在_.find之后安全地获得财产

时间:2016-09-16 08:04:00

标签: underscore.js

正如标题所说,我试图在找到之后安全地获得对象的属性。

让我们假设我有这样的数组:

var ppl = [
    { id: 1, name: 'Smith' },
    { id: 2, name: 'Wesson' },
    { id: 3, name: 'Remington' },
    { id: 4, name: 'Colt' }
];

所以我试图通过id来获得这位尊敬的绅士之一的名字,所以我使用_.find

var person = _.find(ppl, function(p) { return p.id === 2; });

我正在寻找一种安全获取name链中_的方法。类似的东西:

var personName = _.chain(ppl)
                  .find(function(p) { return p.id === 2; })
                  .get('name') //<-- can't find appropriate method :(
                  .values();

Ofc我可以用if(person&amp;&amp; person.name)这样的支票来做...或者甚至编写我自己的原型方法,但不想重新发明轮子。

2 个答案:

答案 0 :(得分:2)

当你使用get时我假设你使用的是lodash而不是下划线。如果是这样,那么您可以使用版本4.14.0中引入的defaultTo

var ppl = [
  { id: 1, name: 'Smith' },
  { id: 2, name: 'Wesson' },
  { id: 3, name: 'Remington' },
  { id: 4, name: 'Colt' }
];

var nullPerson = {
  id: 0, 
  name: 'null'
}

var personName = _.chain(ppl)
  .find({id: 99})
  .defaultTo(nullPerson)
  .get('name')
  .value();

console.log(personName);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

答案 1 :(得分:2)

我相信GruffBunny是正确的,因为你似乎在使用Lodash而不是Underscore。我也觉得答案中提供的解决方案非常优雅,但我想展示一种替代方案。

注意:我将提供一个Underscore答案,因为问题被标记为Lodash,因为OP似乎对此感兴趣

Underscore.js

我总觉得有点尴尬的一件事就是你所处的确切情况 - 链(数组) - &gt;做操作 - &gt;找到 - &gt;做其他事情。 Underscore中的Object函数略有偏差。但是,我们仍然可以尝试这样做:

&#13;
&#13;
var ppl = [
    { id: 1, name: 'Smith' },
    { id: 2, name: 'Wesson' },
    { id: 3, name: 'Remington' },
    { id: 4, name: 'Colt' }
];

function findName(id) {
  return _.chain(ppl)
  .findWhere({id: id}) // <- shorter syntax than _.find and does the same as supplying your own function. 
                      // It's even shorter than the already short fat arrow syntax which would be: (p => p.id === 2)
  .pick('name') // <- extract a new object that has a single property "name"
  .map() //<- 1. for objects, it's equivalent to mapping the values only, e.g., _.map(_.values(obj)) 
         //^- 2. if no argument is specified, it defaults to _.identity
  .first() // <- since the previous step returns an array of one value this step unwraps it and leaves you with a plain value
  .value(); // end chain, return result
}

console.log("Find ID = 2:", findName(2));
console.log("Find ID = 42:", findName(42));
console.log('Find ID = "2" (string value):', findName("2"));
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
&#13;
&#13;
&#13;

所以,这将完成这项工作,但有点尴尬。你缺少.get,所以你必须采摘 - &gt;地图 - &gt;先做相同的事。它并不严格,但它并不是那么好。另一种方法是将单个结果保存在一个数组中,以便运行其他函数。所以,你可以这样做

_.chain(ppl)
  .where({id: id}) //it's basically "filterWhere" like _.findWhere but it returns all results in an array. In this case, it would be a single result purely so we can do the below
  .map('name') //<- allows you to map by name of the property but only with arrays
  .first() // <- still have to unwrap
  .value();

让我们看看等效的

Lodash

Lodash更好一些,因为它的语法更平滑,并且对对象的处理也更好一些,因此您不必面对需要将它们保存在一个值的数组中的情况。

&#13;
&#13;
var ppl = [
    { id: 1, name: 'Smith' },
    { id: 2, name: 'Wesson' },
    { id: 3, name: 'Remington' },
    { id: 4, name: 'Colt' }
];

function findName(id, defaultName) {
  return _.chain(ppl)
  .find({id: id}) //<- Lodash does not have _.findWhere but the normal _.find already handles this
  .get('name') // <- see, much simpler! You can also supply a second argument which would be returned as a default value
  .value();
}

console.log("Find ID = 2:", findName(2));
console.log("Find ID = 42:", findName(42));
console.log('Find ID = "2" (string value):', findName("2"));
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
&#13;
&#13;
&#13;