an odd fellow

仕事のメモ

関数の引数にスプレッド構文を使った場合

背景

React書いていると以下のような...propsのような記述がたまに見られるが、どういう振る舞いになるのか少し混乱したから整理する。

const DeleteButton = ({className, ...props}) => (
  <span className={[style.root, className].join(' ')} {...props}>
    <TrashCanIcon />
    <Baloon>削除する</Baloon>
  </span>
);

スプレッド構文

ドットを3つつなげたこれはスプレッド構文と呼ばれている。Iterableなオブジェクトの中身を展開してくれるようだ。

スプレッド構文 - JavaScript | MDN

これらは以下の3つの場面で使うことができる。 1. 関数呼び出し 2. Arrayリテラル 3. Objectリテラル

2,3は想像が付くんだが関数呼び出しのときの振る舞いがうまく想像できない。

実験

とりあえず使ってみる。

const hage = ({...props}) => {console.log(props)};
hage({a:1});
// => {a: 1}

const hage=(props) => {console.log(props)};と変わらないっぽい? propsの中身を一度展開し、再度Objectにしたものをpropsという名前で束縛しているのか? そもそも({a, b}) => {}って引数に渡されたObjectからabのプロパティだけを抽出する構文だよね?なんかおかしくね?

const hige = ({...props}) => {console.log(a)};
hige({a: 1});
// => ReferenceError: a is not defined

これでa1が束縛されるんじゃないかと思ったんだけどな…。

propsの中身を一度展開し、再度Objectにしたものをpropsという名前で束縛している?

これが正解っぽい

const huge = ({a, ...props}) => {console.log(a, props)};
huge({a: 1, b: 2, c: 3});
/// => (1, {b: 2, c: 3})

なるほど?...を付けたら問答無用で残りは引き渡ってくれるのかー。

結論

というわけで最初の例はなんでもごちゃごちゃに渡されてくるpropsからclassNameだけをチュ出し、残りの要素は再度propsに束縛するという感じか。納得はしてないが振る舞いはわかった。

再掲

const DeleteButton = ({className, ...props}) => (
  <span className={[style.root, className].join(' ')} {...props}>
    <TrashCanIcon />
    <Baloon>削除する</Baloon>
  </span>
);