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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21428980/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 20:54:17  来源:igfitidea点击:

ko.utils.arrayMap, but only return part of the array

javascriptknockout.js

提问by Adam Marshall

I am using some of the Knockout utility functions described brilliantly here: http://www.knockmeout.net/2011/04/utility-functions-in-knockoutjs.html

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

I want to do an arrayMap to select certain properties based on a condition, e.g.

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

return ko.utils.arrayMap(myObservableArray(), function (item) {
    return item.Label;
});

Say for example this produces the following output:

例如,这会产生以下输出:

[null, "", "SomeLabel", null, "SomeOtherLabel"]

I want to select the properties based on a condition, so I try:

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

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

However then you end up with an array like:

但是,您最终会得到一个数组,例如:

[undefined, undefined, "SomeLabel", undefined, "SomeOtherLabel"]

I've also tried this:

我也试过这个:

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

but you get:

但你得到:

[false, false, "SomeLabel", false, "SomeOtherLabel"]

So I am then having to do:

所以我必须这样做:

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

Which will give me:

这会给我:

["SomeLabel", "SomeOtherLabel"]

Is there a more efficient way of accomplishing this, in one shot, using ko.utils or similar?

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

回答by Hans Roerdinkholder

As you noticed, with ko.utils.arrayMap it is expected your callback returns something. SO this is a 'dumb function' that always appends the return value of the callback to the array. Returning undefined, null or false does not omit the value from the resulting array.

正如您所注意到的,使用 ko.utils.arrayMap 预计您的回调会返回一些内容。所以这是一个“哑函数”,它总是将回调的返回值附加到数组中。返回 undefined、null 或 false 不会忽略结果数组中的值。

arrayFilter allows for no way to modify the filtered item: the original item will be pushed to the result array.

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

So in short, this cannot be done more efficiently with the ko.utils.array* functions. You could combine them and make the code a bit more verbose, perhaps even put them in a computed:

简而言之,使用 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;
    });
});

But this is the best you can do. I chose to first apply the filter, and afterwards do the mapping, because it seems to me the mapping would be more expensive than the filtering. But that's just a hunch.

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

Maybe a library such as Underscore provides methods to do this directly.

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

It's also fairly easy to write such a method yourself (and possible put it in ko.utils if you wish)

自己编写这样的方法也相当容易(如果你愿意,可以把它放在 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;
    },

your mapping callback can now return falsy values such as 0, "", false, null or undefined, and they won't end up in the array.

您的映射回调现在可以返回假值,例如 0、""、false、null 或 undefined,并且它们不会出现在数组中。

If you want to permit a few of the above values anyway (such as 0 or ""), then just change the line:

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

if (mapResult)

to something more strict, like:

更严格的东西,比如:

if (mapResult !== undefined && mapResult !== null)

回答by ebohlman

Hans's second method can be shortened a little to

汉斯的第二种方法可以缩短一点

ko.utils.arrayMapFilter = function (array, mapping) {
    var result = [], mapResult;
    ko.utils.arrayForEach(ko.unwrap(array || []), function (item) {
        mapResult = mapping(item);
        if (mapResult) {
            result.push(mapResult);
        }
    });
    return result;
};

which will work on either a plain array or an observableArray(returning a plain array in both cases). It's worth timing it since some JS engines' internal implementations of foreach(which ko.utils.arrayForEachuses if available) are alleged to be slower than using a forloop on the array, though the difference is likely to be small.

这将适用于普通数组或observableArray(在两种情况下都返回普通数组)。值得对其进行计时,因为据称某些 JS 引擎的内部实现foreachko.utils.arrayForEach如果可用,则使用)比for在数组上使用循环慢,尽管差异可能很小。