简体   繁体   English

在 JavaScript 中,如何通过解构和短路评估有条件地为 object 赋值?

[英]In JavaScript, how can I conditionally assign value to object with destructuring and short circuit evaluation?

Let's say I have this set up:假设我有这个设置:

const objA = { name: "Jacob", email: "jacob@email.com" };
const objB = { lastName: "Smith" };

Why can I do this:为什么我可以这样做:

const lastName = objA.lastName || objB.lastName;

But not this?但不是这个?

const { lastName } = objA || objB;

Was able to re-create above example in dev tools.能够在开发工具中重新创建上述示例。

My real world application: I have "normal" and "legacy" account roles, and after querying both types of roles, I'd like to be able to do:我的真实世界应用程序:我有“正常”和“传统”帐户角色,在查询这两种类型的角色后,我希望能够:

const { schoolAdmin } = account || legacyAccount;

... but instead have to do: ...而是必须这样做:

const schoolAdmin = account.schoolAdmin || legacyAccount.schoolAdmin;

Which is admittedly not a big deal, but I feel like there's something I'm missing and that I could use destructuring here.诚然,这没什么大不了的,但我觉得我缺少了一些东西,我可以在这里使用解构。 Jr dev, sorry if this is a dummy question, (Sometimes there is no account. and sometimes there is an account that doesn't have the schoolAdmin role! Likewise with legacyAccount.) Jr dev,抱歉,如果这是一个虚拟问题,(有时没有帐户。有时有一个帐户没有 schoolAdmin 角色!与 legacyAccount 类似。)

What Happens发生什么了

The reason why you can't, is because an empty object returns true.你不能的原因是因为一个空的 object 返回 true。 Try !!{} in devtools for example, it returns true.例如,在 devtools 中尝试!!{} ,它返回 true。

Knowing this, it's easy to realize that the ||知道这一点,很容易意识到|| operator will always select the first object.接线员总是 select 第一个 object。

To test this, you can try the following:要对此进行测试,您可以尝试以下操作:

const objA = { name: "Jacob", email: "jacob@email.com" };
const objB = { lastName: "Smith" };
let { lastName } = objB || objA; // Returns Smith

And:和:

const objA = { name: "Jacob", email: "jacob@email.com" };
const objB = { lastName: "Smith" };
let { lastName } = objA || objB; // Returns undefined

A Proposed Solution建议的解决方案

The solution to this is to spread the two object into one.解决方案是将两个 object 分散为一个。 Note that the order of the two matters, as explained below!注意两件事的先后顺序,下面会解释!

const { lastName } = { ...objB, ...objA };
  • If objA has a lastName property, it will be used regardless if objB has the property, because it will just overwrite it.如果 objA 具有 lastName 属性,则无论 objB 是否具有该属性都将使用它,因为它只会覆盖它。

  • If objA doesn't have the property, lastName will not be overwritten from objB, so its value will be returned.如果 objA 没有该属性,则不会从 objB 覆盖 lastName,因此会返回其值。 (Or undefined if none of them has the property) (如果它们都不具有该属性,则为未定义)

As explained in the comments ||正如评论中所解释的那样|| doesn't evaluate to union of objects, it returns the second one不评估对象的联合,它返回第二个

You can do this instead:你可以这样做:

const { lastName } = { ...objA, ...objB };

It does create a union它确实创建了一个工会

Your expression is trying to assign lastName from a property in the object returned from the sub-expression on the right side of the = assignment operator.您的表达式试图从=赋值运算符右侧的子表达式返回的 object 中的属性分配lastName That right side sub-expression, objA || objB右边的子表达式objA || objB objA || objB evaluates to objA , which has no lastName property, so your lastName variable receives a value of undefined . objA || objB计算结果为objA ,它没有lastName属性,因此您的lastName变量收到值undefined

You could either just use objA , and provide a default value from objB , if the property doesn't exist in objA :如果objB中不存在该属性,您可以只使用objA并提供objA的默认值:

const { lastName = objB.lastName } = objA;

Or, you can spread objA and objB into a single object, and destructure from that:或者,您可以将objAobjB到单个 object 中,并从中解构:

const { lastName } = { ...objB, ...objA };

When spreading, reverse the order.撒的时候,顺序倒过来。 The last object spread overwrites values from the first object. So, if you want to prefer the value from objA , list objA last.最后一个 object 覆盖了第一个 object 的值。因此,如果您想要更喜欢 objA 的值, objAobjA最后。

This spreading option provides a satisfying symmetry, but is likely to be less efficient.这种扩展选项提供了令人满意的对称性,但可能效率较低。 From a performance perspective, the first option is better.从性能的角度来看,第一个选项更好。 But, for me, personally, I think the code you don't like provides better clarity with performance as good as you can get:但是,就我个人而言,我认为您不喜欢的代码提供了尽可能好的性能和清晰度:

const lastName = objA.lastName || objB.lastName;

This is completely unambiguous and performs no unnecessary operations.这是完全明确的,不会执行不必要的操作。

It should also be pointed out that neither of my solutions is strictly equivalent to the non-destructuring approach.还应该指出的是,我的两种解决方案都不是严格等同于非解构方法。 If objA.lastName is a falsy value besides undefined , ( "" , null , 0 , or false ), then objB.lastName would be used, whereas in both of my solutions, the falsey objA.lastName would be used.如果objA.lastName是除undefined之外的虚假值( ""nullfalse ), objB.lastName 0而在我的两个解决方案中,将使用虚假的objA.lastName Thanks to VLAZ for mentioning this in the comments.感谢VLAZ在评论中提到这一点。

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

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