解构数组中所有元素的对象属性

16
在最基本的形式中,拥有一个对象数组:
let arr = [
  {val:"a"},
  {val:"b"}
];

如何使用解构来获取值['a', 'b']
获取第一个值很容易:
let [{val:res}] = arr; //res contains 'a'

使用rest运算符可以获取数组中的所有值:
let [...res] = arr; //res contains all objects

结合这些,我希望能够使用:

let [...{val:res}] = arr; //undefined, expected all 'val's (['a', 'b'])

上面的代码返回undefined(在FF中测试)。进一步的测试似乎表明,在使用对象解构时添加剩余操作符也不会使用迭代,而是返回原始对象,例如let [...{length:res}] = arr; //res= 2。其他尝试,如let [{val:...res}] = arr;let [{val}:...res] = arr;会产生语法错误。

使用其他方法也很容易做到,比如在数组上使用map,但大多数情况下我都会在解构多个级别时遇到这个问题(一个包含自己属性的对象数组,其中包含一个数组)。因此,我真的在努力了解如何仅使用解构来解决它。

为方便起见:a test fiddle

编辑

如果我没有解释清楚问题的目标,我表示歉意。我不是在寻找特定问题的解决方案,而只是想找到正确的语法来使用解构。

否则,第一个问题是:在上面的示例中,为什么let [...{val:res}] = arr;不返回所有值(['a', 'b'])。第二个问题是:使用嵌套对象解构的rest操作符的正确语法是什么?(我很确定我在这里混淆了一些定义)。似乎后者不受支持,但我还没有遇到任何说明它为什么不支持的文档。

当你像这样解构时,你到底期望 res 变成什么?“all vals”是什么? - Bergi
@Bergi 我本来期望它返回 ['a', 'b'] (因为它是 let [{val:res}] = arr;let [...res] = arr; 的组合) - Me.Name
@Me.Name "第二个问题是:如何使用rest操作符与嵌套对象解构的正确语法?(我很确定我在这里混淆了一些定义)。" 请参阅ECMAScript文档中的SpreadElement是什么?它是否与MDN上的Spread操作符相同? - guest271314
@Me.Name 是否要求不使用函数调用或循环? - guest271314
5个回答

10

1
谢谢你的回答。我知道可以使用 map,我也可以使用 for({val:v} of arr) console.log(v); 来结合解构和循环,甚至可以在 map 中使用解构,但是如果剩余运算符可以用于对象本身,并且可以在嵌套属性上使用解构,为什么不能在对象解构中使用剩余运算符呢?我找不到关于它支持的文档,但也没有找到不支持的文档。 - Me.Name
每次处理一个元素确实是可能的,但如果要处理未知数量的条目,你会如何做到呢?(不包括 for..of - Me.Name
@Me.Name (不包括 for..of) 为什么不能使用 for..of?有哪些要求? - guest271314
for...of 是一个迭代器循环,每次迭代都会声明变量,与 for...infor 循环不同。 - synthet1c
@guest271314 目标是找到一种通用的方法。例如,能够在内部数组上使用它,例如获取[{foo:1, arr:[ {val:"a"}, {val:"b"}]},{foo:2, arr:[ {val:"c"}, {val:"d"}]} ]中的所有值。 - Me.Name
显示剩余4条评论

9
为什么let [...{val:res}] = arr;不能返回所有的值(['a', 'b'])?
看起来你把rest语法和数组解析混淆了。
如果你给[someElements, ...someExpression]赋值,那么这个值就会被测试是否可迭代,然后由迭代器生成的每个元素都会分配给相应的someElements变量。如果你在解构表达式中使用rest语法,将创建一个数组,并执行迭代器直到结束,同时填充该数组以生成的值。然后将该数组分配给someExpression
所有这些赋值目标都可以是其他解构表达式(任意嵌套和递归评估),或变量或属性的引用。
因此,如果你做let [...{val:res}] = arr,它将创建一个数组并用arr的迭代器中的所有值填充该数组:
let {val:res} = Array.from(arr[Symbol.iterator]())

现在你可以明白为什么会出现“undefined”,以及使用诸如[...{length:res}]这样的方法是如何产生结果的。下面是另一个例子:
let [{val:res1}, ...{length: res2}] = arr;
console.log(res1) // 'a'
console.log(res2) // 1 (length of `[{val: 'b'}]`)

如何使用解构来获取值 ['a', 'b'] ? 不行。应该使用 map 方法。

@guest271314 为什么?如果您指的是您的帖子,那么这与我的回答有什么关系呢? - Bergi
“可以使用解构来仅获取值['a','b']吗?”您的回答中的“根本不行”部分。 通过在“=”右侧为从输入数组检索到的每个预期值声明唯一变量,然后将定义的变量推送到数组中,可以实现此目的。 尝试使用spread元素通过{[prop]: [...res]}扩展解构赋值中的数组,但尚未找到将“a”扩展到分配的下一个索引的方法。 - guest271314
如果您声明多个变量,则无法针对任意长度的数组进行操作。如果使用循环,则不再是解构。 - Bergi
没有考虑到任意长度的数组,因为OP中的数组只包含四个元素。对于任意长度的数组,第一印象是尝试将变量分配为对象的属性,而不是例如a;不确定是否可能。将尝试这种方法。在这里发表评论的原因是因为你的回答中有"一点也不"的部分。如果你对你回答的那部分满意,我也在这里。同时还评论了,因为你可能会注意到对回答的那部分有可能改进的地方 - guest271314
看你的意思是什么 ... - guest271314

1

除了使用回调函数映射值之外

let arr = [{ val: "a" }, { val: "b" }];

console.log(arr.map(o => o.val));

你可以在参数列表中使用解构,并仅使用值进行返回。

let arr = [{ val: "a" }, { val: "b" }];

console.log(arr.map(({val}) => val));


嗨,尼娜。感谢回答我的帖子。我总是喜欢你的帖子和你提供的简洁回答 :) 但在这种情况下,它不是关于特定场景,而是要找到通用语法解决方案。我认为会有一种语法来处理未知数量元素的解构,因此可以将其用于例如[{foo:1, arr:[ {val:"a"}, {val:"b"}]},{foo:2, arr:[ {val:"c"}, {val:"d"}]} ] - Me.Name
1
我的误解是你想要达到的结果。我非常依赖示例,对我来说不清楚你想要实现什么。我看不出对象是源对象还是目标对象。如果您包括源和目标,可能会更清晰明了。 - Nina Scholz
我们的目标是找出如何(以及是否)可以使用解构来获取多个值。由于存在rest运算符(let[...res]=arr;是有效的)并且允许嵌套属性,那么为什么 let [...{val:res}] = arr;不能提取所有的值。我一直认为这是我的疏忽,但现在我开始担心这是不可能的。这不是关于特定问题或示例的,所以恐怕我无法给出特定的源和目标,只能提供一些例子。 - Me.Name

1

此时,您可以同时使用For of循环ES6对象解构

let arr = [{val:"a"},{val:"b"}];
    
    
    for (const item in arr){
        const {val} = arr[item];
        console.log(val);
    }


0

在解构赋值之前,您可以声明赋值目标;在解构目标时,通过来自解构源的值设置赋值目标索引的值

let arr1 = [{val: "a"}, {val: "b"}];

let arr2 = [{"foo":1,"arr":[{"val":"a"},{"val":"b"}]}
           , {"foo":2,"arr":[{"val":"c"},{"val":"d"}]}];

let [res1, res2] = [[], []];

[{val: res1[0]}, {val: res1[1]}] = arr1;

[{arr: [{val:res2[0]}, {val:res2[1]}]}
, {arr: [{val:res2[2]}, {val:res2[3]}]}] = arr2;

console.log(res1, res2);

你可以选择在目标处使用rest元素来通过在对象模式后包含逗号运算符来收集源处的值,以返回从对象中提取的值

let arr = [{val: "a"}, {val: "b"}];

let [...res] = [({val} = arr[0], val), ({val} = arr[1], val)];

console.log(res)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接