function を new してオブジェクトを生成した際に、外部から変数を見られないようにするにはどうしたらいいのか。
java でいうと下記の当たり前(?)なこと。
public class Person { private String name_ = null; public Person(String name) { name_ = name; } public String getName() { return name_; } public static void main(String args[]) { System.out.println(new Person("basyura").getName()); //=> basyura } }
コンストラクタで与えられた name にアクセスできるのは、public な getName メソッド経由のみ。これを javascript でやりたい。
その1 - 素直に書いてみる
var Person = function(name) { var name_ = name; this.getName = function() { return name_ } } var person = new Person('basyura'); print(person.getName()); //=> basyura
インスタンス変数には _ を付けたい派なのだけど、入れ替えなくてもいける。
var Person = function(name) { this.getName = function() { return name } } var person = new Person('basyura'); print(person.getName()); //=> basyura
でも、name がインスタンス変数なのかグローバル変数なのか分かりにくい。間違えて使ってしまうこともあるかもしれない。
その2 - prototype で拡張したい場合は?
メモリ効率とかを考えると prototype を使いたいところ。
var Person = function(name) { var name_ = name; } Person.prototype.getName = function() { return name_; } var person = new Person('basyura'); print(person.getName()); //=> ReferenceError: name is not defined
getName から name_ は見えない。スコープが違うから。でも prototype 使いたい。
var Person = function(name) { this.name = name; } Person.prototype.getName = function() { return this.name; } var person = new Person('basyura'); print(person.getName()); //=> basyura
見えた。けど、外からも見える。
var person = new Person('basyura'); print(person.name); //=> basyura
その3 - 無理なの?
関数でスコープを作って、その1と2を混ぜる。
var Person = (function() { var name_; var Constructor = function(name) { name_ = name; } Constructor.prototype.getName = function() { return name_; } return Constructor; }()) var person = new Person('basyura'); print(person.getName()); //=> basyura print(person.name); //=> undefined
できた。インスタンス変数を閉じ込めつつ、prototype による拡張もできる(function スコープ内での定義に限る)。
ねんがんの カプセルか をてにいれたぞ!
そうでもない。
var person1 = new Person('aaaaaaa'); var person2 = new Person('bbbbbbb'); print(person1.getName()); //=> bbbbbbb print(person2.getName()); //=> bbbbbbb
コンストラクタ関数を定義するときにクロージャを使ってるから同じところを見ちゃうのか・・・な・・・。