【问题标题】:Is there any library or native syntax could return a new object with key of an array and value of a callback function?是否有任何库或本机语法可以返回具有数组键和回调函数值的新对象?
【发布时间】:2020-10-17 09:49:15
【问题描述】:

我想做一些像下面这样的函数 xxx

const source = ['a','b','c']

const result = source.xxx(key => key + 'hello')

//  or 

const result  = xxx(source,() => key => key + 'hello')

console.log(result)

// result
{
 'a': 'ahello',
 'b': 'bhello',
 'c': 'chello'
}

我知道我可以编写如下代码来获取它

const source = ['a','b','c']

const xxx = (source: any[],callback) => {
 let result = {}
 source?.forEach(key => result = Object.assign({},result,{key: callback(key)})
 return result
}

const result = xxx(source,(key) => key + 'hello')

但是是否有任何库或本机语法可以做到这一点而无需我自己编写?

【问题讨论】:

  • 这个问题的“任何库”部分对于 SO 来说是题外话。图书馆推荐被特别称为题外话。

标签: typescript


【解决方案1】:

您可以使用Object.fromEntries(),它将使用一对键和值创建一个对象。在 TypeScript 术语中,它需要或 Iterable<[string | number | symbol, any]>

结合default parameter values你可以很简单的表达这个函数:

const xxx = (source = []) => {
  return Object.fromEntries(
    source.map(key => [key, `${key}hello`])
  );
}

console.log(xxx(["a", "b", "c"]));
console.log(xxx());

Playground Link

但是,由于 .map() 涉及创建一个全新的数组,以便立即使用和丢弃,您可以使用 generator function(另请参阅 TypeScript Deep Dive 在线书籍中的 this chapter )

type Mapping<T, U> = (x: T) => U;

function* toEntries<T, Key, Value>(
    keyMapper: Mapping<T, Key>, 
    valueMapper: Mapping<T, Value>, 
    data: Iterable<T>
): Generator<[Key, Value]> {
    for (const item of data) {
        yield [keyMapper(item), valueMapper(item)];
    }
}

这将切断中间人,只根据需要提供键值对,而无需一次完成所有操作并将它们包装在一个数组中。

这样,创建新对象的调用就变成了

const xxx = (source: any[] = []) => {
  return Object.fromEntries(
    toEntries(x => x, x => `${x}hello`, source)
  );
}

Playground Link

function* toEntries(keyMapper, valueMapper, data){
    for (const item of data) {
        yield [keyMapper(item), valueMapper(item)];
    }
}

const xxx = (source) => {
  return Object.fromEntries(
    toEntries(x => x, x => `${x}hello`, source)
  );
}


console.log(xxx(["a", "b", "c"]));

【讨论】:

    【解决方案2】:

    JavaScript 标准库中没有任何内容可以满足您的要求,但您可以通过多种方式实现。从表现力的角度来看,我喜欢mapObject.fromEntries

    const xxx = (source) => Object.fromEntries(
        source.map(key => [key, `${key}hello`])
    );
    

    现场示例:

    const xxx = (source) => Object.fromEntries(
        source.map(key => [key, `${key}hello`])
    );
    
    const source = ['a','b','c'];
    console.log(xxx(source));

    这确实涉及一些中间数组等。

    我也喜欢VLAZ's approach using a generator function

    最简单的方法是循环:

    const xxx = (source) => {
        const result = {};
        for (const key of source) {
            result[key] = `${key}hello`;
        }
        return result;
    };
    

    现场示例:

    const xxx = (source) => {
        const result = {};
        for (const key of source) {
            result[key] = `${key}hello`;
        }
        return result;
    };
    
    const source = ['a','b','c'];
    console.log(xxx(source));

    有些人会把它硬塞进reduce,但这对你没有任何好处:

    const xxx = (source) => source.reduce((result, key) => {
        result[key] = `${key}hello`;
        return result;
    }, {});
    

    现场示例:

    const xxx = (source) => source.reduce((result, key) => {
        result[key] = `${key}hello`;
        return result;
    }, {});
    
    const source = ['a','b','c'];
    console.log(xxx(source));

    【讨论】:

    • 避免中间数组的.map() 的替代方法是使用生成器函数。在许多情况下可能是矫枉过正,但它仍然是一种选择。 Playground Link
    • @VLAZ - 哦,太好了!! (也许作为答案发布?这是一个很好的方法。) 当然,理论上这涉及创建结果对象,但如果你不明确使用它们,JavaScript 引擎可能会优化它们。 .
    • 是的,它会创建很多结果对象,但至少不会一次创建一个完整的数组,这也会变成对象。希望引擎足够聪明,可以进一步优化这一点。
    猜你喜欢
    • 2020-12-05
    • 2019-01-05
    • 2017-03-13
    • 2013-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多