0
0

More than 3 years have passed since last update.

JavascriptのES6以降のクラスでイミュータブルプロパティを定義

Last updated at Posted at 2020-12-20

Object.definePropertyを利用

  • Object.definePropertyメソッドを使って、読み込み専用のプロパティを定義する。
  • writableはデフォルトはfalseなので、設定がなくてもいい。明示するのはコードリーディング上はありかも。
security.js

export default class Security {
  setCsrf(value) {
    //第1引数は自身のインスタンス、第2引数はプロパティ名
    Object.defineProperty(this, "csrf", {
      //値を設定
      value: value,
      //読み込み専用
      writable: false,
    });
  }
}

  • 利用は以下。
run.js

import Security from "[任意のパス]/security";

const s = new Security();
//プロパティを設定
s.setCsrf("A");

//プロパティから値取得
console.log(s.csrf); // "A"を表示

//setを試みる
s.csrf = "B" //readOnlyの例外発生

複数のプロパティをインスタンス時に設定する

  • Object.propertiesを使う方法もあるが、オブジェクトリテラルの値をすべてする場合は、以下のようにするのもありかと思う。
  • オブジェクトリテラルをモデルクラスにするときに以下のようにすると良いかもしれない。
model.js

export default class Model {

 /**
  * 初期化
  */
 constructor(dataSet) {
   this._setProperties(dataSet);
 }

 /**
  * オブジェクトリテラルの値をプロパティに設定
  */
 _setProperies(dataSet) {
   for(const [key, value] of Object.entries(dataSet)) {
     this._setProperty(key, value);
   }
 }

 /**
  * プロパティ設定
  */
 _setProperty(name, value) {
    Object.defineProperty(this, name, {
      value: value,
      writable: false,
    });
  }
}


  • 利用は以下。
run.js

import Model from "[任意のパス]/model";

//オブジェクトリテラルを作成
const dataSet = {"key1": "val1", "key2": "value2"};

//インスタンス化
const m = new Model(dataSet);

console.log(m.key1); // val1を表示
console.log(m.key2); // val2を表示

継承によりプロパティ定義を隠蔽

  • 設定処理を他のクラスで利用する場合は継承で設定を隠蔽する。
extended.js
import Model from "[任意のパス]/model.js"

export default class Extended extends Model {

  constructor(dataSet) {
    super(dataSet);
  }

}

指定名のプロパティを必ず定義する

  • 指定のプロパティを必ず定義し、undefinedエラーを防止する。
  • 可変引数で必ず設定したいプロパティ名を設定。
  • オブジェクトリテラルにプロパティがあるかを判別してない場合は、nullを設定。(初期値は任意のものでよいと思う。空文字や-1などプロパティの性質に合わせる)
model.js
export default class Model {

 /**
  * 初期化
  */
 constructor(dataSet, ...names) {
   this._setProperties(dataSet, names);
 }

 /**
  * オブジェクトリテラルの値のうち、指定名を必ずプロパティに設定
  */
 _setProperies(dataSet, names) {
   //指定のプロパティ名でプロパティを設定。
   // 値が無い場合はnullを設定
   for(const name of names) {
     const value = (name in dataSet) ? dataSet[name] : null;
     this._setProperty(name value);
   }
 }

 /**
  * プロパティ設定
  */
 _setProperty(name, value) {
    Object.defineProperty(this, name, {
      value: value,
      writable: false,
    });
  }
}

  • 上記の定義を継承により隠蔽。
extended.js
import Model from "[任意のパス]/model.js"

export default class Extended extends Model {

  constructor(dataSet) {
    super(dataSet, "prop1", "props2", "prop3");
  }

}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0