ko.utils.arrayMap,但只返回数组的一部分

Ada*_*all 6 javascript knockout.js

我正在使用一些出色的Knockout实用程序函数:http://www.knockmeout.net/2011/04/utility-functions-in-knockoutjs.html

我想做一个arrayMap来根据条件选择某些属性,例如

return ko.utils.arrayMap(myObservableArray(), function (item) {
    return item.Label;
});
Run Code Online (Sandbox Code Playgroud)

比方说,这会产生以下输出:

[null, "", "SomeLabel", null, "SomeOtherLabel"]
Run Code Online (Sandbox Code Playgroud)

我想根据条件选择属性,所以我尝试:

return ko.utils.arrayMap(myObservableArray(), function (item) {
    if (item.Label && item.Label !== "") {
        return item.Label;
    }
});
Run Code Online (Sandbox Code Playgroud)

然而,你最终得到一个数组,如:

[undefined, undefined, "SomeLabel", undefined, "SomeOtherLabel"]
Run Code Online (Sandbox Code Playgroud)

我也试过这个:

return ko.utils.arrayMap(myObservableArray(), function (item) {
    return (item.Label && item.Label !== "") ? item.Label : false;
});
Run Code Online (Sandbox Code Playgroud)

但你得到:

[false, false, "SomeLabel", false, "SomeOtherLabel"]
Run Code Online (Sandbox Code Playgroud)

所以我必须这样做:

var itemsWithLabels = ko.utils.arrayFilter(myObservableArray(), function (item) {
    return (item.Label && item.Label !== "");
});
return ko.utils.arrayMap(itemsWithLabels, function (item) {
    return item.Label;
});
Run Code Online (Sandbox Code Playgroud)

哪个会给我:

["SomeLabel", "SomeOtherLabel"]
Run Code Online (Sandbox Code Playgroud)

有没有更有效的方法来实现这一点,一次性使用ko.utils或类似?

Han*_*der 9

正如您所注意到的那样,对于ko.utils.arrayMap,预计您的回调会返回一些内容.所以这是一个'哑函数',总是将回调的返回值附加到数组.返回undefined,null或false不会忽略结果数组中的值.

arrayFilter不允许修改过滤的项目:原始项目将被推送到结果数组.

简而言之,使用ko.utils.array*函数无法更有效地完成此操作.您可以将它们组合起来并使代码更加冗长,甚至可能将它们放入计算中:

var itemsWithLabels = ko.computed(function () {
    return ko.utils.arrayMap(ko.utils.arrayFilter(myObservableArray(), function (item) {
        return item.Label && item.Label.length;
    }), function (filteredItem) {
        return filteredItem.Label;
    });
});
Run Code Online (Sandbox Code Playgroud)

但这是你能做的最好的事情.我选择先应用过滤器,然后进行映射,因为在我看来映射会比过滤更昂贵.但这只是一种预感.

也许像Underscore这样的库提供了直接执行此操作的方法.

自己编写这样的方法也相当容易(如果你愿意的话可以把它放在ko.utils中)

    ko.utils.arrayMapFilter = function (array, mapping) {
        array = array || [];
        var result = [], mapResult;
        for (var i = 0, j = array.length; i < j; i++) {
            mapResult = mapping(array[i]);
            if (mapResult) {
                result.push(mapResult);
            }
        }
        return result;
    },
Run Code Online (Sandbox Code Playgroud)

你的映射回调现在可以返回虚假值,如0,"",false,null或undefined,它们不会在数组中结束.

如果你想要允许上面的一些值(比如0或""),那么只需更改一行:

if (mapResult)
Run Code Online (Sandbox Code Playgroud)

更严格的事情,如:

if (mapResult !== undefined && mapResult !== null)
Run Code Online (Sandbox Code Playgroud)