初めに
fill()
でずぼらして初期化したら思った挙動にならなかったので備忘録。
実際のコードを引っこ抜いてちょっと変えてるので変な感じになってるかも。
JavaScriptは最近やり始めましたがよくわからんですね。
起こったこと
以下のような変数を作成した
export const FuncA = (): HogeHoge => {
const [a, setA] = useState("0");
const [b, setB] = useState("0");
retunrn {
parameter: {a,b},
setter: {setA,setB}
};
}
fill(funcA)
をしたparameters
配列のそれぞれの要素を突っ込んだテーブルを以下みたいな感じで作る。
function TableBody(params: Params){
const parameters = Array(params.lineCount).fill((FuncA));
return (
<table>
<thead>...</thead>
<tbody> { getLines(parameters) } </tbody>
</table>
);
}
...
function getLines(foo: Array<FuncA>) {
return ([...Array<number>(foo.length)].map((_, i) => {
return (
<tr>
<td>{ i + 1}</td>
<td>
<label>A: <input type="number" value={foo.parameter.a} onChange={(e) => foo.setter.setA(e.target.value)} /></label><br />
<label>B: <input type="number" value={foo.parameter.b} onChange={(e) => foo.setter.setB(e.target.value)} /></label>
</td>
</tr>
)
}));
}
全てのinputが独立して変更されることを想定していたが、
画面上でinputの値を変更したばあい全ての行の値が変更された。
FuncA
の定義をexport const FuncA(){...}
にしてfill( ()=> FuncA())
とかにもしたけど同じだった。
よくわからないけど直した
fill()
をやめてmap()
で割り当てたら独立した。
fill(0)
をしている場合上記みたいなことにならないので、
非プリミティブ型の場合は参照で引きたわされるのだろうか。
(そもそも関数を変数に入れること自体がこれまでなかったのでそこの挙動の把握も実は微妙)
const parameters = [...Array(params.lineCount)].map(() => FuncA());
おそらくこの部分の記載に基づくもの
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/fill
Polyfillのが同等の実装らしいので少し見たところ
var O = Object(this);
のところが多分そうかなとは思った。
Objectのコンストラクタのページは404だったが、Objectクラスの説明に以下の記載があった。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object
Object コンストラクターは、指定された値のオブジェクトラッパーを生成します。
- 値が null または undefined である場合、空のオブジェクトを生成して返します。
- それ以外の場合は、与えられた値に関連する型のオブジェクトを返します。
- 値がすでにオブジェクトであった場合は、その値を返します。
少し調べた感じJavaScriptもプリミティブ型はオブジェクトではなさそうなので、
プリミティブ型は2つ目の挙動、それ以外の場合は3つ目の挙動になるのだろうか。
この「その値」というのが複製ではなく引き渡したオブジェクト自体がかえるという意味であれば納得できる。