どうも。つじけ(tsujikenzo)です。このシリーズでは2021年8月からスタートしました「ノンプロ研EffectiveJavaScript輪読会」についてお送りします。
前回のおさらい
前回は、「メソッドをプロトタイプに格納しよう」「プライベートデータの格納にはクロージャを使おう」を2本まとめてお届けしました。
[EffectiveJavaScript輪読会5]メソッドをプロトタイプに格納しよう
どうも。つじけ(tsujikenzo)です。このシリーズでは2021年8月からスタートしました「ノンプロ研EffectiveJavaScript輪読会」についてお送りします。前回のおさらい前回は、「newに依存しないコンス...
今回は、「インスタンスの状態は、インスタンスオブジェクトにだけ保存する」「thisの暗黙的な結合を理解しよう」 を2本まとめてお届けします。
テキスト第4章「オブジェクトとプロトタイプ」の項目36、項目37に対応しています。
今日のアジェンダ
- インスタンスの状態は、インスタンスオブジェクトにだけ保存する
- thisの暗黙的な結合を理解しよう
インスタンスの状態は、インスタンスオブジェクトにだけ保存する
ツリーデータ構造を実装するクラスは、それぞれのノードが、子ノードの配列を含むことになります。
子ノードの配列(インスタンスの状態)を、プロトタイプに書いてしまうと、構造が壊れてしまいます。
function myFunction5_36_01() {
function Tree(x) {
this.value = x;
}
Tree.prototype = {
children: [],//インスタンスの状態
addChild: function (x) {
this.children.push(x)
}
}
const left = new Tree(2);
left.addChild(1);
left.addChild(3);
const right = new Tree(6);
right.addChild(5);
right.addChild(7);
const top = new Tree(4);
top.addChild(left);
top.addChild(right);
console.log(top.children); // [ 1, 3, 5, 7, { value: 2 }, { value: 6 } ]
}
なので、このように、インスタンスの状態は、インスタンスオブジェクトだけに保存するようにします。
コンストラクタで、インスタンス変数に格納します。
function myFunction5_36_02() {
class Tree {
constructor(x) {
this.value = x;
this.children = [];//インスタンスの状態
}
addChild(x) {
this.children.push(x)
}
}
const left = new Tree(2);
left.addChild(1);
left.addChild(3);
const right = new Tree(6);
right.addChild(5);
right.addChild(7);
const top = new Tree(4);
top.addChild(left);
top.addChild(right);
console.log(left.children); // [ 1, 3 ]
console.log(right.children); // [ 5, 7 ]
console.log(top.children); // [ { value: 2, children: [ 1, 3 ] }, { value: 6, children: [ 5, 7 ] } ]
}
書籍では、以下の3点をまとめていました。
あたまにいれておくと、あとで便利だなと思ったので、書き残しておきます。
- 変化するデータを共有すると問題が多い
- プロトタイプは、そのすべてのインスタンスで共有される
- インスタンスごとに変化する状態は、インスタンスオブジェクトに保存する
thisの暗黙的な結合を理解しよう
暗黙的なthisには気をつけようという話は、なんどもしてきました。
use strictモードで、引数を展開させたコールバック関数を、アロー関数で書こうというのが、現時点の最適解です。
function myFunction05_37_01() {
'use strict'
class CSVreader {
constructor(separators) {
this.separators = separators || [","];
const regexpArray = this.separators.map(sep => "\\" + sep[0]).join("|");
this.regexp = new RegExp(regexpArray);
}
read(str) {
const lines = str.trim().split(/\n/);
return lines.map(line => line.split(this.regexp));
}
}
const reader = new CSVreader();
console.log(reader.read("a,b,c\nd,e,f\n")); //[ [ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ] ]
const reader2 = new CSVreader(["_"]);
console.log(reader2.read("a_b_c\nd_e_f\n")); //[ [ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ] ]
}
まとめ
以上で、「インスタンスの状態は、インスタンスオブジェクトにだけ保存する」「thisの暗黙的な結合を理解しよう」を2本まとめてお届けしました。
次回は、「スーパークラスのコンストラクタは、サブクラスのコンストラクタから呼び出す」「スーパークラスのプロパティ名は、決して再利用しない」 を2本まとめてお届けします。