【问题标题】:syntax for es6 destructuring from an array into an objectes6 从数组解构到对象的语法
【发布时间】:2016-03-22 05:43:11
【问题描述】:

我正在读取一个带有制表符分隔值的文件,我想将其转换为一个具有命名属性的哈希数组。

我研究过the MDN page on Destructuring assignment,但其中一些涉及更多的示例对我来说没有意义,而且我没有看到导致单个对象的语法。

这是我目前所得到的:

return File.readFile(filepath, 'utf8')
.then((fileContents) => fileContents.split('\n').map((line) => {
    // here is where I'd convert the line of tab-separated
    // text into an object with named properties

    // this is fake, broken syntax
    return ({ prop_a: [0], prop_b: [2], prop_c: [1] }) = line.split('\t');
}));

需要注意的几点:

  • 我正在使用带有节点 v5 的 babel。如有必要,我愿意加载额外的解析或转换插件。
  • File.readFile 是一个简单的 ES6 Promise 包装器,围绕节点原生 fs.readFile(path, opt, callback) API。

我正在寻找一个可以拆分line 并从中任意分配到新创建的对象的语句。我认为解构是实现这一目标的正确方法,但也许需要的是例如休息或传播的一些创造性使用。

// sample input text
Ralphette   dog 7
Felix   cat 5

// desired output
[ { name: 'Ralphette', species: 'dog', age: '7' },
  { name: 'Felix'    , species: 'cat', age: '5' }
]

感谢您的帮助!


回答

听起来没有办法仅通过解构来做到这一点。然而,在混合中引入 IIFE 会产生一种具有较少异国情调的解构的单线。这是我使用的代码,基于@Amadan 的回答:

return File.readFile(filepath, 'utf8')
.then((fileContents) => (fileContents.length === 0)
    ? []
    : fileContents
        .split('\n')
        .map((line) => (([ name, species, age ]) => ({ name, species, age }))(line.split('\t')))
)

它非常简洁,因此我建议不要在实际项目中使用它。

如果几年后,有人发现了一种无需 IIFE 的方法,我希望他们会发布它。

【问题讨论】:

  • 顾名思义,你不能用destructuringconstruct一个对象。解构是关于从集合中提取数据,而不是创建集合。为此使用对象或数组字面量。
  • @Tom,我提供了更新我的答案以解决您的 IIFE 评论

标签: javascript ecmascript-6


【解决方案1】:

可能不是您想要的,但最接近的可能是

(x => ({ prop_a: x[0], prop_b: x[2], prop_c: x[1] }))(line.split('\t'));

但这可能是最容易做到的

var parts = line.split('\t');
return { prop_a: parts[0], prop_b: parts[2], prop_c: parts[1] };

虽然我可能被证明是错误的,但我认为你想要的东西不能通过解构赋值来完成。

【讨论】:

  • 我想我明白你在做什么了:你定义了一个接受数组并返回对象的 IIFE,然后将拆分传递给 IIFE。简洁,但有效。
【解决方案2】:

您不能将数组直接解构为对象

这个答案不是将所有东西捆绑在一个大杂乱的函数中,而是采用分解的方法。这里的各个函数更容易编写、维护和测试。执行单一任务的小函数也更容易在程序的其他部分重用。

const lines = x => x.split("\n")
const cells = x => x.split("\t")
const makeObject = ([name, species, age]) => ({name, species, age})

const data = "Ralphette\tdog\t7\nFelix\tcat\t5"
const result = lines(data).map(x => makeObject(cells(x)))

console.log(result)
// [ { name: "Ralphette", species: "dog", age: "7" }
// , { name: "Felix", species: "cat", age: "5" }
// ]

如果你有一个compose 函数,它会变得更干净一些

const compose = (f,g) => x => f(g(x))

const result = lines(data).map(compose(makeObject,cells))

console.log(result)
// [ { name: "Ralphette", species: "dog", age: "7" }
// , { name: "Felix", species: "cat", age: "5" }
// ]

如果几年后,有人发现了一种无需 IIFE 的方法,我希望他们会发布它。

已经有几年了,所以这里对您的答案进行了修改,不涉及立即调用的函数-

File
  .readFile(filepath, 'utf8')
  .then
    ( fileContents => 
        fileContents.length === 0
          ? []
          : fileContents
              .split('\n')
              .map(line => line.split('\t'))
              .map(([ name, species, age ]) => ({ name, species, age }))
    )

这实际上与我上面的原始答案相同,只是效率较低,因为它使用了两次对 map 的调用。以下是如何将 linescellsmakeObject 连接到您的原始代码 -

File
  .readfile(filepath, 'utf8')
  .then
    ( fileContents => 
        fileContents.length === 0
          ? []
          : lines(fileContents).map(line => makeObject(cells(line))
    )

还有一件事......

File.readFile 是一个简单的 ES6 Promise 包装器,围绕节点原生 fs.readFile(path, opt, callback) API

Node 现在附带Promise-based API for the fs module。不用定义自己的包装器,您可以简单地 -

const { readFile } = require("fs").promises

readFile(filePath, 'utf8').then(results => ...)

【讨论】:

    【解决方案3】:

    这可能是另一个最接近的:

    var parts = line.split('\t');
    var [name, species, age] = parts;
    return {name, species, age};
    

    【讨论】:

    • 对象字面量可以简化为{name, species, age}
    猜你喜欢
    • 2023-03-03
    • 2020-02-18
    • 2017-07-24
    • 2020-12-16
    • 2018-08-30
    • 1970-01-01
    • 2020-08-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多