マイナー・マイナー

隠れた名作の発掘が生きがい。

JavaScriptで静的に追加されたメソッドからのアクセス権について


スポンサードリンク

JavaScriptでは、オブジェクトを作成した後にそのオブジェクトに対してプロパティやメソッドを追加することができる。けれど、その挙動がなかなか分かりづらく、とりわけアクセス権の理解に苦労しています。というわけで、アクセス権に関するコードをいろいろ書いてみて、その挙動を勉強しました。

そもそもオブジェクトとは

JavaScriptにはクラスという概念はなく、プロトタイプという概念がある。プロトタイプとはオブジェクトの元になるオブジェクトのこと。考え方としては、下記のような関数(コンストラクタとみなす)を宣言し、

var Data = function(info) {
  this.info = info;
};


これをnew演算子インスタンス化することによってオブジェクトが生成される。

var hoge = new Data('Hoge');


これがプロトタイプ(オブジェクト)になり、このオブジェクトに対してプロパティやメソッド(プロパティに追加される関数をとりわけそう呼ぶ)を追加することができる。

静的プロパティ/静的メソッド

JavaScriptでは関数もオブジェクトである、というわけでコンストラクタ(関数)にもプロパティやメソッドを追加することができる。インスタンスを生成せずに利用できるプロパティ、メソッドをそれぞれ静的プロパティ、静的メソッドと呼びます。静的メソッドから静的プロパティへのアクセス権の挙動を調べてみます。

// コンストラクタ宣言
var Data = function(info) {
  this.info = info;
};

// 静的プロパティ追加
Data.language = 'Japanese';

// 静的メソッド追加
Data.setInfo = function(info) {
  this.info = info;
};

Data.getInfo = function() {
  return this.info;
};

Data.setLanguage = function(language) {
  this.language = language
};

Data.getLanguage = function() {
  return this.language
};

インスタンスを生成せずに呼び出したときの挙動

Data関数を直接呼び出したときの挙動を下記コードで検証しました。結果はコメントの通り。

Data('Hoge');

document.writeln(Data.getInfo()); // undefined
Data.setInfo('Piyo');
document.writeln(Data.getInfo()); // Piyo
document.writeln(Data.info);  // Piyo
document.writeln(window.info); // Hoge

コンストラクタのDataはnewしないと単なる関数。そして、thisは自身の関数を参照しているオブジェクトを結合する。上のコードの場合、参照元はGlobalオブジェクト(ブラウザで検証した場合はwindow)なので、Data('Hoge');はグローバル変数にinfoを定義したことになる。


Data('Hoge');を実行した段階では、オブジェクト階層は次のような感じになっていました。

Global (window)
∟Data
 ∟getInfo
 ∟setInfo
 ∟getLanguage
 ∟setLanguage
 ∟language = "Japanese"
∟info = "Hoge"


続いてData.getInfoを呼び出した場合、Data内のinfoを探しにいき、そこにはinfoが無いので結果はundefinedになる。Data.setInfoを呼び出すと、Data内にinfoを定義するため、後続のData.getInfoやData.infoには"Piyo"が取得できる。


Data.language = 'Japanese';のようにプロパティを追加すると、それはData内にlanguageを追加したことになるため、アクセサは直感通りの挙動となる。

document.writeln(Data.getLanguage()); // "Japanese"
Data.setLanguage('English');
document.writeln(Data.getLanguage()); // "English"
document.writeln(Data.language);  // "English"

インスタンス経由で呼び出したときの挙動

下記のようにインスタンス化すると、

var hoge = new Name('Hoge');


infoのみをプロパティとして持つhogeオブジェクトができた。

Global (window)
∟hoge
 ∟info = "Hoge"


なので、インスタンス経由でgetInfo等を呼びだそうとしても、メソッドがないと怒られる。Data.XXXのように静的プロパティや静的メソッドを追加した場合、これらはDataオブジェクトに対して追加されたメソッドであり、Dataから生成されるインスタンスには追加されないようです。

document.writeln(hoge.getInfo()); // has no method
hoge.setInfo('Piyo');  // has no method
document.writeln(hoge.getInfo()); // has no method
document.writeln(hoge.info);  // Hoge

document.writeln(hoge.getLanguage()); // has no method
hoge.setLanguage('Piyogo');  // has no method
document.writeln(hoge.getLanguage()); // has no method
document.writeln(hoge.language);  // undefined