MENU

JavaScript構文オブジェクトゲッター・セッター

【JavaScript】 ゲッター・セッターとは?必要性はあるのか?

更新日:2021/02/03

 

 

JavaScriptにはゲッターとセッターという機能があります。

 

正直知らなくてもプログラムを作成できますが、他者のコードを見るとき困るので調べてみました。

 

 

2020/02 意味不明な文章が多かったので大幅改稿しました。

ゲッター(Getter)とセッター(Setter)とは

 

ゲッターとセッターとはアクセサープロパティに関連付けられた関数です。
アクセサープロパティは、プロパティ値のセットや取得アルゴリズムをカスタイマイズすることを目的としています。

 

プロパティの種類

 

まずは簡単に、プロパティの種類についてお伝えします。
プロパティには、データプロパティとアクセサープロパティの2種類があります。

 

データプロパティ

 

通常のプロパティです。
代入された値をそのまま保存し、保存された値をそのまま返します。

 

データプロパティの定義

 


obj.prop = 100;
obj.func = function(){};

 

JavaScriptでプロパティ値として有効なのは、プリミティブまたはオブジェクトです。

 

関数の実体は関数オブジェクトなので、メソッドもデータプロパティです。

 

アクセサープロパティ

 

アクセサープロパティは、代入された値を任意の方法および形式で保存するセッター関数と、保存された値または任意の値を任意の形式で返すゲッター関数が定義されたプロパティです。

 

次のコードは、単純なアクセサープロパティの定義例です。

 

アクセサープロパティの定義例

 

let value = 0;

const obj = {
    get prop(){ // ゲッター関数:値を得る
        return value * 2;
    },
    set prop( param ){ // セッター関数:値をセット
        value = param / 3;
    },
};

 

上のコードを実行すると、obj内にpropという名前のアクセサープロパティが作成されます。
その後、ゲッター関数とセッター関数がpropに結びつけられます。

 

ゲッター関数とセッター関数は、値をそのままセットしたり返したりする必要はありません。

 

ゲッター関数とセッター関数

 

ゲッター関数とセッター関数は、一般的には外部変数への入出力をおこなう処理をおこないます。

 

ゲッター関数

 

ゲッター関数は、オブジェクトリテラル内で次の形式で記述します。

get プロパティ名(){
    ・・・関数コード
    return 戻り値;
}

 

ゲッター関数は引数がありません。

 

関数内のコードは、外部に確保してある変数をそのまま、あるいは一つまたは複数の変数を加工して戻り値として返します。
変数を使用せず、固定値を返すこともできます。

 

セッター関数

 

セッター関数も同様に、オブジェクトリテラル内で次の形式で記述します。

 

set プロパティ名( value ){
    ・・・関数コード
}

 

セッター関数は引数を一つだけ受け取ります。
関数コードは、受け取った引数を外部変数に代入する処理を記述するのが一般的です。

 

引数の型チェックをおこなうケースもあります。

 

アクセサープロパティからデータを取得する

 

アクセサ―プロパティは、代入の右辺などで値が取得されるとき、ゲッター関数が呼び出されます。

 

アクセサ―プロパティからデータを取得する

 

const data = obj.prop;

 

内部的に関数が呼び出されますが、後ろに()を記述しません。
記述するとエラーになります。

 

const data = obj.prop();  // Uncaught TypeError: obj.prop is not a function

 

次のように関数を返した場合、

 

get prop(){ return function(){}; }

 

()を付けると返された関数が実行されます。

 

const data = obj.prop();

 

 

アクセサープロパティでデータをセットする

 

アクセサ―プロパティは、代入先として指定されるとき、代入値を引数としたセッター関数が呼び出されます。

 

次のように100を代入すると、

 

obj.prop = 100;

 

引数の値を100として、セッター関数が呼び出されます。

 

set prop( value ){ // value = 100
    ・・・関数コード
}

 

関数が呼び出されますが、データの取得と同様に、()を付けるとエラーになります。

 

obj.prop() = 100;  // Uncaught TypeError: obj.prop is not a function

 

 

格納先変数の取り扱い

 

現実的な使用方法としては、セッター/ゲッターで値の格納先として扱われる変数は、クロージャの特徴などを利用して隠蔽するのが望ましいです。

 

ゲッター/セッターの現実的な使用例

 


function getObj(){

    let _name = ""; // 値保存用変数

    return {

        get name(){ // ゲッター
            return _name; 
        },
        set name( param ){ // セッター
            if( typeof (param) === "string" || param instanceof String){ // 文字列かどうかの検査
                _name = param;
            }
        },
    }
};

const obj = getObj();

obj.name = "Taro";   // セッターが呼ばれる
console.log( obj.name );            // ゲッターが呼ばれる

 

重要な変数を関連するコード以外からアクセスできないようにすることを、カプセル化と呼びます。
カプセル化については、次の記事を読んでみてください。
【JavaScript】 JSにおけるカプセル化手法

 

アクセサープロパティの利点

 

わざわざアクセサープロパティを用意しなくても、setName()やgetName()などのメソッドでもいいのでは、と思う人も多いのではないでしょうか。

 

アクセサープロパティは引数の数が決まっているので、柔軟性に欠ける面があります。
引数で取得する値の条件指定をしたいときなどは、アクセサープロパティでは実現できません。

 

アクセサープロパティの利点は、上書きができないことです。

 

データプロパティは代入操作により、値が変更されます。
メソッドだったが、いつのまにか数値プロパティに変わっていたという想定外の結果になる可能性もあります。

 

obj.prop = function(){}; // メソッド
obj.prop = 100; // 数値プロパティ

 

しかしアクセサープロパティは、代入値を引数とした関数が呼ばれるので、プロパティそのものを別のものに変更されることがありません。

 

このような特徴を考慮しながら、アクセサープロパティにするかどうかを決定していく必要があります。

 

Object.freezeメソッドやObject.definepropertyメソッドを使用することで、データプロパティを上書き不可にすることも可能です。

 

ゲッター/セッターはセットでなくてもよい

 

ゲッター/セッターをセットで用意する必要はありません。
片方だけでもOKです。

 


function getObj( name ){

    let _name = name; // 値保存用変数

    return {

        get name(){ // ゲッター
            return _name;
        },
        set newName( param ){ // セッター
            _name = param;
        },
    }
};

const obj = getObj( "hanako" );

obj.name = "Taro"; // セッターがないのでエラー
                    // TypeError: setting getter-only property "name"

 

上の例はセッターが定義されていないので、nameプロパティは取得専用となります。

 

その逆で、newNameプロパティはセッターのみのため、設定専用プロパティとなります。

コンストラクターとプロタイプでゲッター/セッターを定義する

 

ゲッター/セッターはプロトタイプでも定義できます。

 

コンストラクターでthisのプロパティを定義して、プロタイプでthisを操作するゲッター/セッターを記述すればOKです。

 

 


const obj = function( name ){
    this._name = name;
};
obj.prototype={
    get name(){ // ゲッター
        return this._name;
    },
    set name( param ){ // セッター
        if( typeof (param) === "string" || param instanceof String){
            this._name = param;
        }
    },
};

const a = new obj( "Taro" );
a.name = "Hanako";
console.log( a.name );

 

 

コンストラクターとプロタイプについては、次の記事を参考にしてみてください。

 

参考:【JavaScript】 コンストラクターとは?関数とは違うのか?
参考:【JavaScript】 プロトタイプとは?prototypeプロパティはプロトタイプではない件について

 

また、プロタイプメソッドからオブジェクト内にカプセル化された変数にアクセスしたいケースがあります。
こちらについては、次の記事を読んでみてください。
参考:【JavaScript】 JSにおけるprivate変数と定義のひな型パターン

その他の定義の仕方

 

アクセサープロパティは、データプロパティのように . (ドット)表記で定義できません。

 


obj.prop1 = function ( ) { }; // データプロパティの追加
obj.set prop2 = function ( v ) { };  // アクセサープロパティの追加:エラーになる

 

しかし、これまで紹介してきたオブジェクトリテラルでの定義をおこなうと、現在の定義を上書きしてしまいます。

 


obj.prop1 = function ( ) { }; // データプロパティの追加

   // objの内容を新しいオブジェクトで置き換え
   //    →prop1は消える
obj = { 
        get name(){ },
        set name( param ){},
    };

 

JavaScriptがブラウザ上で動作している場合、__defineSetter__または__defineGetter__で定義できます。

 


  // セッターの追加
obj.prototype.__defineSetter__(
      "prop2",                      // プロパティ名
      function( v ){ this._v = v; } // 呼び出す関数
);

  // ゲッターの追加
obj.prototype.__defineGetter__(
      "prop2",                         // プロパティ名
      function(  ){ return  this._v; } // 呼び出す関数
);

 

ただし現在は非推奨となっているので、次のObject.definePropertyを使用します。

 


Object.defineProperty(
         obj.prototype ,           // 追加先のオブジェクト
         "prop2" ,                  // プロパティ名
        {
           set : function( v ){ value = v; },
           get : function(  ){ return value; },
           configurable:true,
        }
);

 

推奨されている方法は、次の記事を読んでみてください。
【JavaScript】 ゲッター/セッター関数を後から変更する方法

けーちゃんおススメJavaScript入門書

  • スラスラ読める JavaScript ふりがなプログラミング
  • プログラム未経験者がJavaScript始めるならコレ!
    コードを掲載して自分で理解しろという投げっぱなしな入門書とは異なり、コードに一つ一つどんなことをやっているかをふりがなという形式で解説しています。
    それでいてJavaScriptの基礎と応用を学べる良書です。
  • これからWebをはじめる人のHTML&CSS、JavaScriptのきほんのきほん
  • JavaScriptの機能を実践で活かすにはHTMLやCSSの知識が不可欠です。
    しかしそれらの知識があることが前提として書かれている書籍が多い中、この本は総合的な知識を身に着けることができます。
    HTMLやCSSの知識も不安な方には、ぴったりの一冊です
  •  

    入門書の役割は、自分のやりたいことをネットで調べることができるようになるための、基礎的な知識の獲得です。
    まずはこれらの本でしっかりと基礎知識を身につけましょう。
    そしてもっと高度なことや専門的なことはネットで調べ、情報が足りないと感じたら書籍を購入してください。


    期間限定情報:
    6/21と6/22は年に一度のプライム会員大感謝祭!
    欲しかったアレが安く手に入るチャンスです
    忘れずにチェックしてください!
    僕は以前のタイムセール祭りで4Kモニタが買ったけど、それより安かったらどうしよう・・・

    ちなみにプライム会員でなくても、無料体験で参加できるようです。
    欲しい商品があるか、確認だけでもしておきましょう。

    記事の内容について

     

    こんにちはけーちゃんです。
    説明するのって難しいですね。


    「なんか言ってることおかしくない?」
    たぶん、こんなご意見あると思います。

    裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。

    そんなときは、ご意見もらえたら嬉しいです。

    ご意見はこちら。
    https://note.affi-sapo-sv.com/info.php

    【お願い】

    お願い

    ■このページのURL


    ■このページのタイトル


    ■リンクタグ


    ※リンクして頂いた方でご希望者には貴サイトの紹介記事を作成してリンクを設置します。
    サイト上部の問い合わせよりご連絡ください。
    ただしサイトのジャンルによっては、お断りさせていただくことがあります。