【问题标题】:Use underscore.js "pluck" on a knockout observable array在淘汰赛 observable 数组上使用 underscore.js “pluck”
【发布时间】:2015-07-15 12:37:39
【问题描述】:

我有一个可观察的对象数组,我想使用 underscore.js 提取值

例如:

ko.observableArray([{
  id: ko.observable(1),
  name: ko.observable("name1")
},
{
  id: ko.observable(2),
  name: ko.observable("name2")
},
...])

我只想提取对象内部的值,而不是整个 observable。

我可以只用一个命令吗?

我试过了:

_.pluck(myArray(), "id()")_.pluck(myArray(), "id"())

但它们分别返回一个未定义数组和“id 不是函数”。

谢谢!

【问题讨论】:

    标签: javascript arrays knockout.js underscore.js


    【解决方案1】:

    简答

    使用_.invoke 而不是_.pluck

    this sample fiddle

    长答案

    _.pluck(list, propertyName) 按文档说明工作:

    可能是最常见的 map 用例的便捷版本:提取属性值列表。

    或者,正如 lodash 文档中更好的解释:_.pluck(collection, path)

    从集合中的所有元素中获取path的属性值。

    所以,如果你这样做:

    _.pluck(myArray(), "id")
    

    你得到的是一个包含所有id 的数组。所有这些id 都是可观察的,就像在原始数组的对象中一样

    但您可以使用_.invoke(list, methodName, *arguments),如文档所述:

    对列表中的每个值调用由 methodName 命名的方法。传递给调用的任何额外参数都将转发给方法调用。

    或者,在lodash版本_.invoke(collection, path, [args])

    在集合中每个元素的路径上调用方法,返回每个调用方法的结果数组。为每个调用的方法提供任何附加参数。如果 methodName 是一个函数,它会被调用,并且 this 绑定到集合中的每个元素。

    这样,你执行每个 observable,并按预期获取它的值:

    _.invoke(myArray(), "id")
    

    注意充满可观察对象的视图模型!

    对这个问题的第一条评论让我包含了这个通知:

    最好的解决方案是使用ko.toJS 将视图模型中的所有可观察对象转换为具有常规属性的常规 JavaScript 对象。完成后,下划线或任何其他库将按预期工作。

    _.invoke 解决方案仅适用于单层可观察对象,如本例所示。如果有多层嵌套的 observables,它将完全失败,因为它在路径的末尾调用一个函数,而不是在路径的每一步,例如,_.invoke 不适用于这种情况:

    var advices = [{
       person: ko.observable({
         name = ko.observable('John')
       }),
       advice: ko.observable('Beware of the observables!')
    }];
    

    在这种情况下,您只能在第一级使用_.invoke,如下所示:

    var sentences = _.invoke(advices,'advice');
    

    但这行不通:

    var names = _.invoke(advices,'person.name');
    

    在这个调用中,只会调用name,但不会调用person,所以这会失败,因为person 是一个可观察对象,因此它没有name 属性。

    注意:lodash 是另一个类似的库,主要兼容下划线,但在某些方面更好

    【讨论】:

    • _.invoke 有效但不是惯用的 - 它对数组内容的性质做出假设。如果id 无法观察到,则您必须更改整个通话。如果整个 path 参数是一个变量,您无法预测它是否会引用可观察对象,那么使用 invoke 根本不起作用。 @CaseyWebb 和 @Mouhong Lin 使用 ko.toJS() 的解决方案更好,因为它们是惯用的,对读者来说立即显而易见且稳定。
    • 我完全同意你的看法。 ko.toJS 是将视图模型转换为“普通”JavaScript 对象的唯一方法。完成后,您可以正常使用下划线函数。我确实理解嵌套的 observables 的含义,这会使它失败。我正在更新我的答案。
    • 我喜欢您提供的解释和示例,所以我选择了这个答案,但是由于您得出的结论与另一位首先回答的发帖者的结论相同,因此我对选择哪个答案感到矛盾。如果这是不正确的,请告诉我,我会改变它。我是一个长期潜伏者,但对提问很陌生。 :)
    • 嗯,有时很难选择最佳答案。我帮不了你。简单地试着想想对于有同样问题的人来说什么答案是最好的,然后选择它。选择解释的质量,如果有疑问,选择最先回答的那个。由你决定。请记住,SO 的目的是帮助人们,所以做你认为对其他人更有帮助的事情。
    【解决方案2】:

    我可以通过使用“地图”功能解决这个问题:

    _.map(myArray(), function(item) {return item.id()});
    

    但我希望使用 pluck,因为它正是这种场景的确切用例。

    【讨论】:

    • 请看我的回答。你要找的是_.invoke
    【解决方案3】:

    因为name是一个函数,那你原来的数组pluck变成一个函数数组,然后用ko.toJS转换成字符串数组怎么样?

    var myArray = ko.observableArray([{
        id: ko.observable(1),
        name: ko.observable("name1")
    },
    {
        id: ko.observable(2),
        name: ko.observable("name2")
    }]);
    
    var names = _.pluck(myArray(), 'name');
    console.log(ko.toJS(names)); // Output: ["name1", "name2"]
    

    【讨论】:

      【解决方案4】:

      先拆开

      _.pluck(ko.toJS(myArray), 'id')
      
      _(ko.toJS(myArray)).pluck('id)
      

      【讨论】:

        猜你喜欢
        • 2013-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-15
        • 1970-01-01
        • 1970-01-01
        • 2012-11-14
        • 2020-05-30
        相关资源
        最近更新 更多