アクセス可能性
以下のコードで、クラスに関する変数へのアクセス可能性を確認する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
class Person member1 = 1 @meber2 = 2 member3: 3 @member4: 4 constructor: -> member5 = 5 @member6 = 6 dispMember1: -> console.log(member1) # 1 # console.log(member2) # Error, not defined # console.log(member3) # Error, not defined # console.log(member4) # Error, not defined # console.log(member5) # Error, not defined # console.log(member6) # Error, not defined console.log("-----") dispMember2: -> console.log(@member1) # undefined console.log(@member2) # undefined console.log(@member3) # 3 console.log(@member4) # undefined console.log(@member5) # undefined console.log(@member6) # 6 console.log("-----") john = new Person() console.log(Person.member1) # undefined console.log(Person.member2) # undefined console.log(Person.member3) # undefined console.log(Person.member4) # 4 console.log(Person.member5) # undefined console.log(Person.member6) # undefined console.log("-----") console.log(john.member1) # undefined console.log(john.member2) # undefined console.log(john.member3) # 3 console.log(john.member4) # undefined console.log(john.member5) # undefined console.log(john.member6) # 6 console.log("-----") john.dispMember1() john.dispMember2() |
各変数へのアクセス可能性は以下の通り。
定義\引用 | クラス | インスタンス | メソッド内 (@なし) |
メソッド内 (@つき) |
|
クラス直下 | v=val |
undef | undef | ○ | undef |
@v=val |
undef | undef | RefError | undef | |
v:val |
undef | ○ | RefError | ○ | |
@v:val |
○ | undef | RefError | undef | |
コンストラクタ | v=val |
undef | undef | RefError | undef |
@v=val |
undef | ○ | RefError | ○ |
この表から、以下のように整理できる。特にpublicなインスタンス・プロパティとstaticなクラス・プロパティを使っていくことになる。
クラス直下で@v:val 定義 |
staticなクラス・プロパティ |
クラス直下でv:val |
publicなインスタンス・プロパティ |
コンストラクタで@v=val |
publicなインスタンス・プロパティ |
クラス直下でv=va l |
privateなクラス・プロパティ |
なお、定義部分のJavaScriptへのコンパイル結果は以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// Generated by CoffeeScript 1.10.0 (function() { var Person; Person = (function() { var member1; member1 = 1; Person.meber2 = 2; Person.prototype.member3 = 3; Person.member4 = 4; function Person() { var member5; member5 = 5; this.member6 = 6; } return Person; })(); }).call(this); |
クラス・プロパティ
クラス直下で@v:val
でプロパティを定義する場合、プロパティはクラスに一つの共有のものとして扱われる。コンパイルされたJavaScriptコードでは正に”[クラス名].[プロパティ名]
“となっている
インスタンスの中から参照する場合も、[クラス名].[プロパティ名]
で参照する。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Person @member: 1 dispMember: -> console.log(Person.member) john = new Person() console.log(Person.member) # 1 john.dispMember() # 1 Person.member++ console.log(Person.member) # 2 john.dispMember() # 2 |
publicなインスタンス・プロパティ
クラス直下でv:val
と定義した場合とコンストラクタで@v=val
と定義した場合は、いずれもインスタンス・プロパティとして扱われる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
class Person member1: 1 constructor: -> @member2 = 2 dispMember: -> console.log(@member1) console.log(@member2) john = new Person() luice = new Person() console.log("--John--") console.log(john.member1) # 1 console.log(john.member2) # 2 console.log("--Luice--") console.log(john.member1) # 1 console.log(john.member2) # 2 john.member1 *= 10 john.member2 *= 10 console.log("--John--") john.dispMember() # 10 # 20 console.log("--Luice--") luice.dispMember() # 1 # 2 |
挙動としては同じなのでどちらでもよさそうだが、インスタンス・プロパティとしてはコンストラクタで定義する形式の方がよいと考えた。
以下のように、それぞれの定義方法でJavaScriptのコードが異なるが、メソッドのようにクラス内で共通化したい場合はprototypeがよいが、そもそもインスタンスごとに異なる値をとることを想定しているプロパティの場合は、thisによる定義の方が意味に即している。
1 2 3 4 5 6 7 8 9 |
class Person member1: 1 # JavaSceiptでは、Personクラスの定義の冒頭で # "Person.prototype.member1 = 1"と定義される。 constructor: -> @member2 = 2 # JavaScriptでは、Person()コンストラクタの中で # "this.member2 = 2"と定義される。 |
privateなクラス・プロパティ
クラス直下でv=val
と定義すると、そのクラスの各インスタンスで共有されたprivateなプロパティになる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Person _member = 1 getMember: -> return _member setMember: (m) -> _member = m john = new Person() luice = new Person() console.log("--John--") console.log(john._member) # undefined console.log(john.getMember()) # 1 console.log("--Luice--") console.log(luice._member) # undefined console.log(luice.getMember()) # 1 console.log() john.setMember(5) console.log(john.getMember()) # 5 console.log(luice.getMember()) # 5 |
JavaScriptコードを見るとクラス宣言の最初でvar宣言されているため、クラス内スコープで外からは見えない変数となる。
1 2 3 4 5 6 |
Person = (function() { var _member; function Person() {} _member = 1; |