简体   繁体   English

es6从数组解构为对象的语法

[英]syntax for es6 destructuring from an array into an object

I'm reading a file with tab-separated values, and I'd like to transform it into an array of hashes with named properties. 我正在读取带有制表符分隔值的文件,我想将其转换为具有命名属性的哈希数组。

I've studied the MDN page on Destructuring assignment , but some of the more involved examples don't make sense to me, and I don't see a syntax that results in a single object. 我已经研究了关于Destructuring assign的MDN页面 ,但是一些更复杂的例子对我没有意义,我没有看到导致单个对象的语法。

Here's what I've got so far: 这是我到目前为止所得到的:

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');
}));

A couple things to note: 有几点需要注意:

  • I'm using babel with node v5. 我正在使用节点v5的babel。 I'm willing to load additional parsing or transform plugins if necessary. 如果需要,我愿意加载额外的解析或转换插件。
  • File.readFile is a simple ES6 Promise wrapper around the node-native fs.readFile(path, opt, callback) API. File.readFile是一个围绕node-native fs.readFile(path, opt, callback) API的简单ES6 Promise包装器。

I'm looking for a single statement that can split line and arbitrarily assign from that into a newly created object. 我正在寻找一个单独的语句,可以拆分line并任意分配给新创建的对象。 I assume destructuring is the right way to pull this off, but perhaps what's needed is eg some inventive use of rest or spread. 我认为解构是解决这个问题的正确方法,但也许所需要的是例如休息或传播的一些创造性使用。

// sample input text
Ralphette   dog 7
Felix   cat 5

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

Thanks for your help! 谢谢你的帮助!


ANSWER 回答

It sounds like there's no way to do this with destructuring only. 听起来似乎没有办法只通过解构来做到这一点。 However, introducing an IIFE into the mix makes for a one-liner with less-exotic destructuring. 然而,在混合物中引入IIFE使得单衬里具有不太奇特的解构。 Here's the code I used, based on @Amadan's answer: 这是我使用的代码,基于@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')))
)

It's quite terse, and for that reason I'd advise against using it in a real project. 它非常简洁,因此我建议不要在真实的项目中使用它。

If, years from now, someone discovers a way to do this without the IIFE, I hope they will post it. 如果,从现在起,有人发现没有IIFE的方法,我希望他们会发布它。

Likely not what you want, but the closest is probably 可能不是你想要的,但最接近的可能是

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

But it is probably easiest to just do 但这可能是最容易做到的

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

While I might be proven wrong, I don't think what you want can be done by destructuring assignment. 虽然我可能被证明是错的,但我不认为你想要的是通过解构分配来完成的。

You can't destructure an array directly into an object 您无法将数组直接解构为对象

Instead of bundling everything together in one big messy function, this answer takes a decomposed approach. 这个答案采用分解的方法,而不是将所有内容捆绑在一个大的混乱功能中。 The individual functions here are easier to write, maintain, and test. 这里的各个功能更易于编写,维护和测试。 Small functions that do a single task are also easier to reuse in other parts of your program. 执行单个任务的小功能也更容易在程序的其他部分重用。

 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" } // ] 


If you have a compose function, it becomes just a bit cleaner 如果你有一个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" }
// ]

If, years from now, someone discovers a way to do this without the IIFE, I hope they will post it. 如果,从现在起,有人发现没有IIFE的方法,我希望他们会发布它。

It's been a few years, so here's an edit to your answer that doesn't involve the immediately invoked function - 已经有几年了,所以这里是你的答案的编辑,不涉及立即调用的功能 -

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

This is effectively doing the same thing as my original answer above, only it's less efficient because it's using two calls to map . 这实际上与我上面的原始答案做了同样的事情,只是效率较低,因为它使用两个调用来map Here's how you can connect lines , cells , and makeObject to your original code - 以下是将linescellsmakeObject连接到原始代码的方法 -

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

And one more thing ... 还有一件事 ...

File.readFile is a simple ES6 Promise wrapper around the node-native fs.readFile (path, opt, callback) API File.readFile是一个围绕node-native fs.readFile (path,opt,callback)API的简单ES6 Promise包装器

Node ships with a Promise-based API for the fs module now. Node现在为fs模块提供了基于Promise的API Instead of defining your own wrappers, you can simply - 您可以简单地 - 而不是定义自己的包装器 -

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

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

This may be another closest: 这可能是另一个最接近的:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM