0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【備忘録】Javascript : private member の設定

Last updated at Posted at 2020-06-13

プライベートメンバー

クラス内部から呼び出すことのできるプロパティ、メソッドの総称。
プライベートメンバーの対にパブリックメンバーが存在するが、これはクラス内外から自由に呼び出しすることが可能なプロパティ、メソッドのこと。プライベートメンバーはクラスの内部からしか呼び出せないように制限することで保守性が高める目的があるそうです。
参考 : https://tomoprog.hatenablog.com/entry/2018/08/19/114223

下記がコード例です。

_base_heightというプライベートなプロパティと_checkArgsというプライベートなメソッドを持つTriangleクラスを定義しています。※Triangleクラスをfunction命令で定義していますがclassで定義することも可能です。詳細は省きますがclass定義はただのシンタックスシュガーなのでここではfunction命令で定義します。

javascript.js

function Triangle(){
  // private プロパティ
  let _base;
  let _height;

  // private メソッド
  let _checkArgs = function(val){
    return (typeof val === 'number' && val > 0);
  }
  // => privateメンバは this._base のようには書かない => 外部から直接代入できてしまう。
  // => privateメンバはインスタンスが存在する間は内部にずっと存在する。

  // 以下、privateメンバにアクセスするためのメソッド
  // 特権メンバとも言う。これらは外部から直接呼び出して使える。
  // つまりprivateメンバにアクセスしたい時には特権メンバを経由する必要がある。
  this.setBase = function(base){
    if (_checkArgs(base)) {
      _base = base;
    }
  }

  this.getBase = function(){
    return _base;
  }

  this.setHeight = function(height){
    if (_checkArgs(height)) {
      _height = height;
    }
  }

  this.getHeight = function(){
    return _height;
  }
}

コメントアウトにも書いてありますがプライベートなメンバーにアクセスするためにはこのクス内に定義されているアクセサーメソッドを経由する必要があります。
これらのアクセさーメソッドのことを特権メソッドというそうです。

実験

では、クラスの外部から直接アクセスが本当にできないのか見てみましょう。
まず、上記のTriangleクラスを使ってgetAreaメソッドを追加しました。
メソッドの中身をみてもらえると分かりますがアクセサーメソッドを使ってプライベートメンバにアクセスしています。

javascript.js

function Triangle(){
  let _base;
  let _height;

  let _checkArgs = function(val){
    return (typeof val === 'number' && val > 0);
  }
  
  this.setBase = function(base){
    if (_checkArgs(base)) {
      _base = base;
    }
  }

  this.getBase = function(){
    return _base;
  }

  this.setHeight = function(height){
    if (_checkArgs(height)) {
      _height = height;
    }
  }

  this.getHeight = function(){
    return _height;
  }
}

// privateメンバに(直接は)アクセスしない普通のメソッドを定義
Triangle.prototype = {
  getArea : function(){
    // 同じクラス内のアクセサーメソッドを使用
    return this.getBase() * this.getHeight() / 2;
  }
}

上記のクラスに対し下記の呼び出しを行います。

javascript.js
// インスタンス t を生成
let t1 = new Triangle();
// インスタンスに対して外部から直接、privateメンバにアクセスしようとしている。
t1._base = 10;
t1._height = 10;
console.log('1.三角形の面積:' + t1.getArea()); // NaN

t1.setBase(10);
t1.setHeight(10);
console.log('1.三角形の面積:' + t1.getArea()); // 50

t1._base = 10t1._height = 10と記述しメンバに直接10を代入しようとしていますがこのまま、t1.getArea()を呼び出しても期待値を出力することができません。

逆に今度はt1.setBase(10)t1.setHeight(10)でアクセサーを使用してセットするとt1.getArea()で期待値50を出力することができました。

一応、下記のパターンでも試します。

javascript.js

let t2 = new Triangle();
// privateプロパティにアクセスするメソッドを使用する。
t2.setBase(10);
t2.setHeight(10);
// アクセサーメソッド
console.log('2.三角形の面積:' + t2.getBase()); // 10
console.log('2.三角形の面積:' + t2.getHeight()); // 10

javascript.js
let t3 = new Triangle();
// privateプロパティに直接代入
t3._base = 10;
t3._height = 10;
console.log('3.三角形の面積:' + t3.getBase()); // undefined
console.log('3.三角形の面積:' + t3.getHeight()); // undefined

t2とt3を比べてもらうと分かりますがアクセサーを使ってセットしたt2の場合、getterでセットした値を再度取得できています。t3の場合は直接、代入した結果、getterで取得しようとしてもundefinedが帰ってきました。

これでprivateなメンバに対してはアクセさーを使わないとアクセスできないことを確認することができました。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?