😺

ブロックスコープ内で {} をオブジェクトとして扱うには「式として書く」必要

に公開5

例えば useState の更新関数などで:

setUser(prev => {
  { name: "kato", age: prev.age + 1 }   // ❌これは文として解釈される
});

これは オブジェクトではなく「ブロック文」 と解釈されてしまい、返り値が undefined になってしまいます。


なぜ? → JS のパーサーは {} を常に「文」として解釈するから

ブロックの最初の {} は 文(statement) なのか オブジェクトの式(expression) なのか曖昧です。
JS では以下のように判断します:

  • { a: 1 } が 文の開始に見えたら → ブロック文として処理される
  • ({ a: 1 }) のように括弧で囲まれていれば → 式として評価される

React の useState 更新関数でよく起きる例

❌ 間違い(返り値がない)

setUser(prev => {
  { ...prev, age: prev.age + 1 };
});

→ この {} は ブロック文
→ リターンされていないので undefined を渡してしまう
→ React は undefined の更新を無視する


正しい書き方1:return を書く

setUser(prev => {
  return { ...prev, age: prev.age + 1 };
});

正しい書き方2:暗黙 return で括弧を使う(よく使う)

setUser(prev => ({
  ...prev,
  age: prev.age + 1,
}));

→ これは ( ) によって オブジェクトが式である と宣言している形


ポイント:括弧は「これは式だよ」と JS に教えている

({ ... })  // オブジェクト式
{ ... }    // 文(ブロック)

React では setState(prev => ({ ... })) のように書くことがよくあるため、括弧は必須です。


さらに深掘り:ブロック内で「オブジェクトを書く」とは?

例:if 文の中にオブジェクトを返したい場合
❌ ブロック文扱い

if (true) {
  { a: 1 };
}

✅ return が必要

if (true) {
  return { a: 1 };
}

または式として括弧で囲む

if (true) {
  const obj = ({ a: 1 });
}

まとめ

書き方 ブロックスコープ オブジェクトとして扱われる?
{ ... } ブロック文 ❌ ならない
({ ... }) ✅ なる
return { ... } return で式になる ✅ なる

React で特に覚えるべきルール

🔹 useState 更新関数

setState(prev => ({ ...prev, x: 1 }));  // ◎
setState(prev => { ...prev, x: 1 });    // ✖ ブロック文

🔹 JSX 中

<div>{ { a: 1 } }</div>   // JSX では式なのでOK(ただし表示は [object Object])

Discussion

junerjuner

これは return が書いていないだけで 式になっておられませんでしょうか?

setUser(prev => {
  { name: "kato", age: prev.age + 1 }   // ❌これは文として解釈される
});

=> 直後の 最初の {) 直前の } で文となって中が式ですね

もしかして こっちのつもりで書いておられましたでしょうか?

setUser(prev => 
  { name: "kato", age: prev.age + 1 }   // ❌これは文として解釈される
);
ryokaryoka
setUser(prev => {
  { name: "kato", age: prev.age + 1 }   // ❌これは文として解釈される
});

コメントありがとうございます!
これはまだjavascriptの文法の理解が浅く。。思い付きな部分がありまして。。
波カッコがつづく場合もあるかなというのが発端で、return省略や文、式の理解が混在しておりました。

いずれにしてもreturnや、()で囲まないとブロック文の中のオブジェクトリテラルが式として認識してもらえないというまとめでした!

1
junerjuner

いや、その行は代入先がないだけで、式として認識されていますよ。
ブロックの中なので。

shiracamusshiracamus

→ この {} は ブロック文

if文などでもブロック文を使いますが、それとはちょっと違いますよね。
外側の {} は関数ブロック(文)で、関数から値を返すにはreturn文が必要です。
内側の {} はオブジェクトリテラル(式)で、変数に代入したりreturnしてないので値(オブジェクト)が捨てられてます。

アロー関数の構文は、式を書く(式の評価値を返す)書き方と、関数ブロックを書く(return文で値を返す)書き方の2種類あります。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions

https://tc39.es/ecma262/#sec-arrow-function-definitions

15.3 Arrow Function Definitions
    Syntax
        ArrowFunction : ArrowParameters => ConciseBody
        ConciseBody :
            ExpressionBody
            { FunctionBody }
1
ryokaryoka

コメントありがとうございます!
おっしゃる通りです!
こういった部分がまだ理解が足りていないのでまたご教示いただけましたら幸いです!