トップへ戻るニュースフォーラムFLASH-ML 過去ログBak@Flaダウンロードよくある質問と答
ログイン
ユーザ名:

パスワード:


パスワード紛失

新規登録
メインメニュー
メイン
   コーダーズルーム【スクリプト系】
     クラス内の変数について
投稿するにはまず登録を

スレッド表示 | 新しいものから 前のトピック | 次のトピック | 下へ
投稿者 スレッド
takiguchi
Åê¹ÆNo.3567
投稿日時: 2004-2-6 14:53
半人前
居住地: 東京
投稿: 38
使用環境:
Win2K,FlashMX2004Pro7.0.1
Re: クラス内の変数について
(2004/2/16 こっそり復活)

■AS2.0でのクラス作成(AS2.0 OOP初級編)

この内容は野中さんのページKatoさんのページを引用して書き換えているだけのつもりですが、
正確に出来ているかは自信ないです。
なので、問題がある場合は早急に削除しますので言って下さい。
Flash5の経験は少しだけあったんですが、一念発起して「迷える子羊の部屋」に
クラス作成について投稿してみましたけど…
投稿してから一週間、はっきり言って初心者が立ち入ってはいけない領域に入ってしまった感じです。
でも、youichさんや野中さんに教えて頂いて、必死こいて勉強したので、
その集大成となっているはずです。きっと…
同じようなことで、悩んでいる方のお役に少しでも立てればと思います。
クラス継承(inheritance)つまり差分プログラミングを中心に書いたつもりでいますが、
インターフェースという強敵等も控えているので、これから勉強していきたいと思います。


//////////////////////////////////////////////////////////////////////Test.as//
class Test{

//////////////////////////////////////////////////////////////////////プロパティ定義//[※註1]
//クラス('static')プロパティ
static var staticProp = "static";

//Test.prototype.protoPropとして定義
var protoProp:String = "prototype";

//Test.prototype.instanceProp1として定義
var instanceProp1:String = "instance";

//Test.prototype.instanceProp2として未定義(宣言のみ)
var instanceProp2:String;


//////////////////////////////////////////////////////////////////////コンストラクタ関数//[※註2]
function Test(myVar:String) {

//this.instanceProp1として定義
instanceProp1 = myVar;

//this.instanceProp2として定義
instanceProp2 = myVar;

}


//////////////////////////////////////////////////////////////////////メソッド定義//[※註1]

//インスタンスからクラスメンバへのアクセス(getter,setter)
//クラスメソッド経由クラスプロパティ取得(特に経由する必要はありません)
function get _staticProp():String{
    return getStaticProp();
    
    //return this.getStaticProp()はエラー:'this.'はインスタンスをスコープするため
    //return Test.getStaticProp()はエラーなし:'Test'はクラス自身をスコープするため
}

static function getStaticProp():String{
    return staticProp;
}

//クラスメソッド経由クラスプロパティ設定
function set _staticProp(myVar:String):Void{
    setStaticProp(myVar);
}

static function setStaticProp(myVar:String):Void{
    staticProp=myVar;
}

    //インスタンスプロパティのgetter,setterは面倒なので省略

}

---------------------------------------------------------------------------
■補足説明
※AS2.0でのクラス定義を「実行空間」で表現する場合、ディレクトリ階層の"例え"を使って考えてみます。
※以下で使用する'this'はTestクラスのインスタンス名と考えてください。
※カレントディレクトリを'..'としています。
※注意! "クラスパス"とは全く関係ない話なので混同しないように気をつけてくださいね。
※AS2.0のみで記述する場合は、読むと余計混乱する場合がありますので、読み飛ばしたほうが良いです。
※自分(初心者)に分かりやすいような言葉で書こうと思って、"例え話"を多用してますが、所詮、諸刃の剣…
※当たれば"天国"、外せば"地獄"ってなもんで…当たってることを願います。

[註1] コンストラクタ関数外の話

  ●クラスを定義する

    「Testクラスを定義する」すなわち「Testという"設計図"を書く」ということは、せっかく書いたその設計図を
    どこかに保存しておかなければなりません。
    その設計図から、いざ!"実物"(オブジェクトとかインスタンス)を作ろう!と思った時、
    設計図を無くしてしまったら、なにも作れなくなってしまいます。ということで…
    「Testという設計図」を書くと、私たちが意識しなくても、Flashが'../Test/'というフォルダの中にしっかりと
    保存してくれます。

  ●スーパークラスを継承('extends')する

    自分が作りたいと思う実物(インスタンス)の設計図(クラス)を、真っ白な紙に一から書いていくのは大変です。
    やんなっちゃいます。
    そこで、誰でも「楽がしたい!」と思うわけです。どうすれば良いかなぁ?と腕組みをしてみると、
    "過去の設計図"に似たようなのがあるかな?…もしあれば、それだけでは"足りない部分"を追加すれば…
    お!いけるジャン!と、ひらめいたとします。
    うまくいけば、ぱくって、ちょこっと付け足すだけで、自分の目的が達成されるわけです。
    楽ちんです(このようなことを差分プログラミングというらしい)。そこで…
    「Testという設計図」を書くのに「Objectという設計図」を"流用"(継承)したとします。
    Flashでは、実際、どんな設計図を書いても、必ずこの「Objectという設計図」を流用することになります。
    これは私たちが意識しなくてもFlashがやってくれます。
    紙に書く設計図に例えるなら、"Objectという設計図"は「鉛筆」「消しゴム」「定規」「紙」…
    など「これが無いと何も出来ない」的な存在なわけです。(鉛筆って…設計図じゃないですけど^^)
    その流用した「Objectという設計図」("流用元の設計図"をスーパークラス)も、
    やっぱりどこかに保存しておかなければなりません。これもFlashが'../Object/'というフォルダの中に
    しっかり保存してくれてます。
    (ちなみに、システムで用意されていて、全クラスに共通するクラスを「メタクラス」というらしいですが、
    このObjectクラスがそれに当たるかどうかは私には分かりません。
    もしかするとクラスコンストラクタとして使われるFunctionクラスがそれに当たるのかもしれません。
    また、全クラスに継承されるObjectクラスは、わざわざ、'extends'を使って継承を明示する必要はないようです。)
    ここで、整理します!
    今までの説明から'../Test/'フォルダと'../Object/'フォルダ
    が最低限存在することになります。次に各フォルダの中身について少し触れます。

    「フォルダ」の中身には、「"流用元の設計図"(スーパークラス)から"追加した部分"」と
    「どの設計図を流用したのか?という"情報"」が入っています。
    ここでの「Testという設計図」で説明すると、前者の「"流用元の設計図"から"追加した部分"」は、
    '../Test/'フォルダ直下に保存されるものと'../Test/prototype/'フォルダに保存されるものとがあります。
    (これは後で説明)
    後者の「どの設計図から流用したのか?という"情報"」は'../Test/prototype/__proto__/'という名前の
    "ショートカット"(リンク先は'../Object/prototype/')で入っています。
    これを難しい言葉で表現すると「ASでの継承の実装」ということになります。

    まとめ…
    今書いた設計図(Test)をサブクラス、流用した設計図(Object)をスーパークラスという表現を使うと、
    ASでのクラス継承の実装は以下のような"参照"となります。
    (サブクラス).prototype.__proto__'←(継承)←(スーパークラス).prototype

  ●ガラス張り('public')である

    'public'というのは、'private'の対義語で、要するに隠し事をせずにガラス張りにすることです。
    設計図に書かれた特性(プロパティ)や機能・処理(メソッド)に'private'を付けなければ
    自動的に'public'になります。従って、ここでの「Testという設計図」の構成要素(エレメント)は
    全て'public'になります。ガラス張りです。スケルトンです。
    しかし、「データの保護」や「プログラムの保守性」等の観点から、'情報隠蔽'という考え方があります。
    通常、プロパティは'private'で情報隠蔽し、メソッドは'public'で外部からのアクセスを許す方法が
    一般的となります。そこで、'private'で情報隠蔽されているプロパティに外部からアクセスするために、
    アクセッサと呼ばれる2種類のメソッド(getter,setter)を用意します。

  ●静的('static')である

    「静的('static')である」というのは「Testという設計図」から作られた(生まれた)"全ての物"で
    「共有する」ことを意味します。
    このように"全ての物"で共有する特性(プロパティ)や機能・処理(メソッド)は、
    全て'../Test/'フォルダ直下に保存されます。
    ここでは'staticProp','getStaticProp()','setStaticProp()'が静的なので
    各々'../Test/'フォルダ直下に保存されることになります。

  ●インスタンスメンバの宣言とインライン初期化

    以下では便宜上、「Testという設計図から"実物"を作る」ことと、
    「'../this/'フォルダを作る」ことは等しいと考えてください。
    いっぱい作ると同名のフォルダが複数作られることになりますが、気にしないで下さい…例えなので(^^;;

    「静的('static')ではない」ということを明言するキーワードは無いみたいなので
    'static'をつけなければそういうことになります。('dynamic'はちょっと違うみたい)
    「Testという設計図」から作られた"実物"(インスタンス)の"要素"(メンバ)が別々になりうる、
    いわば「個性」とも言うべきものをインスタンスメンバと言います。
    そのうち、インスタンス毎に所有する"特性"(プロパティ)のことを「インスタンスプロパティ」と言います。
    「"実物"に、こういった"特性"(インスタンスプロパティ)を含めます!」と宣言(自ら設計図に明記)する時に、
    "デフォルト値"(出荷時設定値みたいな)とも言うべき「ある値」を同時に設定しておく(インライン初期化する)場合と
    設定しない(インライン初期化しない)場合とがあります。

    前者のようにデフォルト値を設定した(インライン初期化した)インスタンスプロパティは、
    そのデフォルト値を'../Test/prototype/'フォルダに保存します。
    ここでは'protoProp','instanceProp1'がインライン初期化されているので、
    各々'../Test/prototype/'フォルダに保存されることになります。
    (出荷元生産工場で出荷時設定値を集中管理しているようなもの)

    '../Test/prototype/protoProp'や'../Test/prototype/instanceProp1'みたいな…

    そして、「Testという設計図」から"実物"(this)を新しく作る(インスタンスを生成する)と、
    '../this/'フォルダが新しく作られて、さらにデフォルト値が保存されている
    '../Test/prototype/'フォルダへの"ショートカット"が、その階層直下に作られます。
    その"ショートカット"の名前は'../this/__proto__/'(リンク先は../Test/prototype/)になります。

    '../this/__proto__/protoProp'(ショートカット)←(参照)→'../Test/prototype/protoProp'(実体)
    '../this/__proto__/instanceProp1'(ショートカット)←(参照)→'../Test/prototype/instanceProp1'(実体)
    みたいな…

    あと、後者のデフォルト値を設定しない(インライン初期化しない)インスタンスプロパティは、
    保存すべき「値」を"まだ"持ってないので、どのフォルダにも保存されてません(undefinedです)。
    ここでは'instanceProp2'がインライン初期化されていないのでデフォルト値はundefinedです。
    ただし、デフォルト値を保存する場所は'../Test/prototype/'フォルダに決められているので、
    後でデフォルト値を設定したければ、'../Test/prototype/'フォルダに自分で直接保存すれば良いのです。
    'instanceProp2'のデフォルト値を自分で直接設定するには、ASで記述すると…

    Test.prototype.instanceProp2 = /*ここにデフォルト値が入ります*/;

    はっきり言って、後でこんな事をするのは面倒です。デフォルト値を設定するのであれば、
    インライン初期化しておくと"自動的に"やってくれるので、便利です。おすすめです。
    逆に、デフォルト値を設定しないのであれば、インライン初期化する必要は無いです。
    このように'../Test/prototype/'フォルダに設定された"全ての"デフォルト値は'../this/__proto__/'の
    "ショートカット"から参照可能となります。

    例えば、後で設定した'instanceProp2'のデフォルト値は下記のように参照可能です。
    '../this/__proto__/instanceProp2'(ショートカット)←(参照)→'../Test/prototype/instanceProp2'(実体)

    実は、この'../Test/prototype/'フォルダには、AS2.0のクラスで"宣言されていない"プロパティも保存することが
    可能です。例えばTestクラスで宣言されていない'extraProp'というプロパティも保存することが可能です。

    Test.prototype.extraProp = /*デフォルト値*/;

    先述した通り、'../Test/prototype/'フォルダに設定された"全ての"デフォルト値は'../this/__proto__/'の
    "ショートカット"から参照可能となるので…

    '../this/__proto__/extraProp'(ショートカット)←(参照)→'../Test/prototype/extraProp'(実体)

    このようなことが出来てしまうのはAS1.0とAS2.0が混在しているためです。
    これは、AS1.0の仕様なので、AS2.0を使う場合はやってはいけません。(やっても混乱するだけです。)
    後で説明することになりますが、AS2.0ではクラスで宣言していないプロパティを
    '../this/'フォルダ直下に置くことは"出来ません"。(dynamicクラスは除く)
    例えば'../this/extraProp'は出来ないことになります。(シンタックスエラーとなります。)

    続いて、インスタンスメソッドについての説明です。
    インスタンスメンバには特性(プロパティ)の他に、機能・処理(メソッド)があり、これを
    「インスタンスメソッド」と言います。しかし、広義な解釈をすると、メソッドはプロパティの一種ともいえます。
    このことについて詳しく紹介されている書籍がありますので詳しくはそちらで…例えば
    ここでのメソッド'_staticProp'(getter,setter)の定義を下記のように書き換えると分かりやすいと思います。
    get,setは便宜上、無視します。

    var _staticProp:Function = function (){…;}; //インライン初期化

    すなわち、"コンストラクタ関数外"でメソッドを

    function _staticProp(){…;};

    のように定義することは、'_staticProp'プロパティを'function(){…;}'でインライン初期化することと
    同じであると考えることが出来ます。従って、この'_staticProp'プロパティは、インライン初期化されているので、
    '../Test/prototype/'フォルダにデフォルト値(機能)として保存されることになります。

    '../Test/prototype/_staticProp'みたいな…

    これもまた'../this/__proto__/'の"ショートカット"から参照可能です。

    '../this/__proto__/_staticProp'(ショートカット)←(参照)→'../Test/prototype/_staticProp'(実体)

    そして重要なのは、実物(インスタンス)の機能・処理(メソッド)というのは、多くの場合
    全てのインスタンスで不変であるということです。
    不変であるものを個々のインスタンスに割り当てる必要は無いので、'../this/'フォルダにその実体は無く、
    '../Test/prototype/'フォルダに保存されたメソッド(便宜上プロトタイプメソッドと命名)への
    "ショートカット"(参照)のみで十分ということになります。

    例えば、浄水器の場合、同じ「機種」(クラス)の「浄水器」(インスタンス)でも、使い方によって
    「ろ材の劣化具合」(インスタンスプロパティ)は個々に違いますが「水を浄化する仕組」(プロトタイプメソッド)
    は不変なわけです。その機種で不変なものを個々に装備するのは、勿体無いないわけで、
    一箇所にまとめましょう!といった考えです。下記はその例(数値は汚れ)…

    泥水(引数:I=200)→浄水器A→すご?くにごった水(戻り値:O=150)
    泥水(引数:I=200)→浄水器B→ちょっとにごった水(戻り値:O=110)

    [浄水器A](インスタンスA)
    ろ材の劣化(インスタンスプロパティ:X=50)
    浄化する仕組(参照)

    [浄水器B](インスタンスB)
    ろ材の劣化(インスタンスプロパティ:X=10)
    浄化する仕組(参照)

    [浄化する仕組](プロトタイプメソッド)
    新品の浄化能力(ローカル変数又は静的プロパティ:Y=100)    O=I-Y+X;

    最後に、インスタンスメンバのデフォルト値として'../Test/prototype/'フォルダに保存する場合と、
    静的('static')メンバとして'../Test/'フォルダに保存する場合とで、一体何が違うのか?ということについて
    説明します。両者とも"全ての実物(インスタンス)で共有するもの"であり、1つしか存在しません。
    この点においては共通していますが、細かい点で異なります。

    まず、'../Test/prototype/'フォルダに保存されたものは、その"ショートカット"(参照)が
    '../this/__proto__/'として自動的に作成されますが、'../Test/'フォルダの"ショートカット"は
    インスタンス(this)に作成されません。従って、'../Test/'フォルダは、直接アクセスしなければなりませんが
    '../Test/prototype/'フォルダは直接アクセスする他に、インスタンス(this)に作成された"ショートカット"から
    でもアクセス出来ることになります。

    あと、静的('static')メソッドは静的('static')プロパティのアクセスのみに限定され、インスタンスプロパティには
    アクセス出来ません。一方で、'../Test/prototype/'フォルダに保存されたプロトタイプメソッドは
    静的('static')プロパティとインスタンスプロパティの両者にアクセスすることが可能です。
    浄水器の例ですと、「水を浄化する仕組」(メソッド)を静的('static')にしてしまうと、
    「ろ材の劣化具合」(インスタンスプロパティ)という値が、その仕組み(メソッド)で利用出来なくなってしまいます。

[註2] コンストラクタ関数内の話

  ●コンストラクタ関数で個性を持たせる

    例え話の続きです…ここでは'../this/'フォルダ直下に保存されるインスタンスプロパティについて説明します。
    コンストラクタ関数すなわち「'../this/'というフォルダを新しく作る時」に、
    インスタンスプロパティに値を"書き込む"(readではない)ように設定しておくと、
    '../this/'フォルダ直下に、そのインスタンスプロパティが"新規作成"されるようになります。
    これが、このインスタンス(this)の個性になります。

    ここでは'instanceProp1','instanceProp2'が、コンストラクタ関数内で値が書き込まれているので
    '../this/'フォルダ直下に"個性"(インスタンスプロパティ)が"新規作成"されます。

    '../this/instanceProp1'(実体)
    '../this/instanceProp2'(実体)
    みたいな…

    しかし、コンストラクタ関数内でインスタンスプロパティに値を"書き込む"ように設定されてなかったり、
    "読み込む"だけでは、'../this/'フォルダ直下に、そのインスタンスプロパティは"新規作成"されません。

    ここでは'protoProp'が、コンストラクタ関数内で何もされていないので、'../this/'フォルダ直下に
    "個性"(インスタンスプロパティ)は"新規作成"されないことになります。

    このように"新規作成"されていない(すなわち存在していない)インスタンスプロパティを読み込もうとすると
    あれ?こんなプロパティ無いぞ?ということで、代わりに"同名のプロパティ"を
    [註1]で述べた'../this/__proto__/'の"ショートカット"から探しに行くことになります。
    '../this/__proto__/'のリンク先である'../Test/prototype/'で"同名のプロパティ"が見つかれば
    デフォルト値とも言うべき値を返し、それでも見つからない場合は"undefined"を返します。

    ['../this/(インスタンスプロパティ)'の検索優先順位]
    高 '../this/' → '../this/__proto__/'(参照) → '../Test/prototype/' 低

    このように、いつまで経ってもデフォルト値を返すような個性の無いプロパティに、後で個性を持たせるには、
    値を書き込んであげれば良いのです。
    たとえ、'../this/__proto__/'に同名のプロパティの"ショートカット"が存在していても、
    '../this/'フォルダ直下に直接値を書き込めば個性が"新規作成"されます。
    'protoProp'に個性を持たせるには、ASで記述すると…

    (インスタンス名).protoProp = /*ここに値(個性)*/;

    そして、個性を持つようになると、その裏側にデフォルト値は隠されてしまいます(隠蔽される)。
    但し、デフォルト値は上書きされたわけではないので、個性を取り除く(deleteする)とデフォルト値が復活します。
    これらは、先述した'../this/(インスタンスプロパティ)'の検索優先順位より説明がつきます。

    var instance1:Test=new Test();

    a = instance1.protoProp; //読み込む
    //存在しないのでショートカットからデフォルト値を返す
    trace(Test.prototype.protoProp == instance1.protoProp); //true

    a = "xxx"
    instance1.protoProp = a; //書き込む
    //個性が新規作成される
    trace(Test.prototype.protoProp == instance1.protoProp); //false

    あと、'../this/'フォルダ直下に保存されるインスタンスプロパティについて注意しなければならないことがあります。
    '../this/'フォルダ直下に新規作成できるプロパティはAS2.0のクラスで"宣言されている"プロパティ
    のみになります。(dynamicクラスは除く)
    AS2.0ではクラスで宣言していないプロパティを'../this/'フォルダ直下に置くことは"出来ません"。
    (シンタックスエラーになります)

    また、コンストラクタ関数内でメソッドを定義すると、個々のインスタンスにそのメソッドを
    割り当てることが出来ますが、これは[註1]でも述べたようにほとんど無意味ですので、メソッドは
    コンストラクタ関数外で定義することをお勧めします。

    推奨できない例

    class Test{
        var instanceMeth:Function;
        function Test() { //コンストラクタ関数
            this.instanceMeth = function (){…;}; メソッド定義
        }
    }

---------------------------------------------------------------------------




※[インスタンス名]?[/インスタンス名]の範囲がそのインスタンスのメンバ
※Testクラスのインスタンスを作成した時点で、データの実体が格納されているメンバは●印、参照型のメンバは○印

[Object] //var Object:Function=new Function();のようなことが勝手にされる
---------------------------------------------------------------------------
//trace(Object instanceof Function) //true
//prototypeはFunctionクラスのプロパティ
//Objectインスタンス(メモリ領域に実体化)のメンバはメモリ内に1つだけ存在

●registerClass()

●[prototype] //Functionクラスのプロパティ
 --------------------------------------------------
 //Object型のprototypeには、以下のメンバが存在
 //__proto__は未定義
 //trace(Object.prototype.__proto__); //undefined

 ●addProperty()
 ●toString()
 ●unwatch()
 ●valueOf()
 ●watch()
 --------------------------------------------------
 [/prototype]
---------------------------------------------------------------------------
[/Object]




[Test] //var Test:Function=new Function();のようなことが勝手にされる
---------------------------------------------------------------------------
//trace(Test instanceof Object) //true
//trace(Test instanceof Function) //true
//prototypeはFunctionクラスのプロパティ
//Testインスタンス(メモリ領域に実体化)のメンバはメモリ内に1つだけ存在

//Testクラスのクラス('static')メンバ
●[staticProp] //Testクラスのクラス('static')プロパティ
 --------------------------------------------------
 //trace(Test.staticProp instanceof String) //true
 ●length
 ●charAt()
 ●charCodeAt()
 ●concat()
 …//その他Stringクラスのメンバ
 //prototypeと__proto__の中身以外は以下省略
 --------------------------------------------------
 [/staticProp]
●getStaticProp() //Testクラスのクラス('static')メソッド
●setStaticProp() //Testクラスのクラス('static')メソッド

//Objectクラスのクラス('static')メンバ
○registerClass() //trace(Test.registerClass == Object.registerClass); //true

//Functionクラスのメンバ
●[prototype] //Functionクラスのプロパティ
 --------------------------------------------------
 //trace(Test.prototype instanceof Object); //true
 //Object型のprototypeには、以下のメンバが存在

 ●protoProp //Testクラスのプロトタイププロパティ
 ●instanceProp1 //Testクラスのプロトタイププロパティ
 ●_staticProp //Testクラスのプロトタイプメソッド

 ○addProperty() //trace(Test.prototype.addProperty == Object.prototype.addProperty); //true
 ○toString() //trace(Test.prototype.toString == Object.prototype.toString); //true
 ○unwatch() //trace(Test.prototype.unwatch == Object.prototype.unwatch); //true
 ○valueOf() //trace(Test.prototype.valueOf == Object.prototype.valueOf); //true
 ○watch() //trace(Test.prototype.watch == Object.prototype.watch); //true
 ○[__proto__]
  --------------------------------------------------
  //trace(instance1.__proto__ instanceof Object); //true
  //trace(Test.prototype.__proto__ == Object.prototype); //true //AS1.0の継承

  ○addProperty() //trace(Test.prototype.__proto__.addProperty == Object.prototype.addProperty); //true
  ○toString() //trace(Test.prototype.__proto__.toString == Object.prototype.toString); //true
  ○unwatch() //trace(Test.prototype.__proto__.unwatch == Object.prototype.unwatch); //true
  ○valueOf() //trace(Test.prototype.__proto__.valueOf == Object.prototype.valueOf); //true
  ○watch() //trace(Test.prototype.__proto__.watch == Object.prototype.watch); //true
  --------------------------------------------------
  [/__proto__]
 --------------------------------------------------
 [/prototype]
---------------------------------------------------------------------------
[/Test]




[instance1] //var instance1:Test=new Test();
---------------------------------------------------------------------------
//trace(instance1 instanceof Object); //true
//trace(instance1 instanceof Test); //true
//TestクラスはObjectクラスを継承

//Testクラス分
//代入前:trace(instance1.protoProp == Test.prototype.protoProp); //true
//代入後:trace(instance1.protoProp == Test.prototype.protoProp); //false prototype隠蔽
○protoProp

●instanceProp1 //trace(instance1.instanceProp1 == Test.prototype.instanceProp1); //false prototype隠蔽
●instanceProp2 //trace(instance1.instanceProp2 == Test.prototype.instanceProp2); //false prototype隠蔽
○_staticProp //trace(instance1._staticProp == Test.prototype._staticProp); //true

//Objectクラス分
○addProperty() //trace(instance1.addProperty() == Test.prototype.addProperty()); //true
○toString() //trace(instance1.toString() == Test.prototype.toString()); //true
○unwatch() //trace(instance1.unwatch() == Test.prototype.unwatch()); //true
○valueOf() //trace(instance1.valueOf() == Test.prototype.valueOf()); //true
○watch() //trace(instance1.watch() == Test.prototype.watch()); //true

○[__proto__]
 --------------------------------------------------
 //trace(instance1.__proto__ instanceof Object); //true
 //trace(instance1.__proto__ == Test.prototype); //true
 //Object型__proto__には、以下のメンバが存在
 
 ○protoProp //trace(instance1.__proto__.protoProp == Test.prototype.protoProp); //true
 ○instanceProp1 //trace(instance1.__proto__.instanceProp1 == Test.prototype.instanceProp1); //true
 ○_staticProp //trace(instance1.__proto__._staticProp == Test.prototype._staticProp); //true

 ○addProperty() //trace(instance1.__proto__.addProperty == Test.prototype.addProperty); //true
 ○toString() //trace(instance1.__proto__.toString == Test.prototype.toString); //true
 ○unwatch() //trace(instance1.__proto__.unwatch == Test.prototype.unwatch); //true
 ○valueOf() //trace(instance1.__proto__.valueOf == Test.prototype.valueOf); //true
 ○watch() //trace(instance1.__proto__.watch == Test.prototype.watch); //true
 --------------------------------------------------
 [/__proto__]
---------------------------------------------------------------------------
[/instance1]


[instance2](var instance2:Test=new Test();)
---------------------------------------------------------------------------
//Testクラス分
○protoProp
●instanceProp1
●instanceProp2
○_staticProp

//Objectクラス分
○addProperty()
○toString()
○unwatch()
○valueOf()
○watch()
○[__proto__]
 --------------------------------------------------
 ○protoProp
 ○instanceProp1
 ○_staticProp
 ○addProperty()
 ○toString()
 ○unwatch()
 ○valueOf()
 ○watch()
 --------------------------------------------------
 [/__proto__]
---------------------------------------------------------------------------
[/instance2]




[その他チェック]
---------------------------------------------------------------------------
var instance1:Test=new Test("test1");
var instance2:Test=new Test("test2");

//インスタンスからクラス'static'プロパティへのアクセス
trace(instance1._staticProp); //出力 static
trace(instance2._staticProp); //出力 static
instance1._staticProp="test3";
trace(instance2._staticProp); //出力 test3

//スコープの移行
trace(instance1.instanceProp1); //出力 test1
delete instance1.instanceProp1;
trace(instance1.instanceProp1); //出力 instance
delete instance1.__proto__.instanceProp1;
trace(instance1.instanceProp1); //出力 undefined
---------------------------------------------------------------------------
youich
Åê¹ÆNo.3595
投稿日時: 2004-2-8 13:43
職人
居住地: kobe
投稿: 349
使用環境:
Tiger
Re: クラス内の変数について

引用:

class Test {
....
//protoPropはコンストラクタ関数内で初期化されてないがインスタンスの数だけ存在する模様(下記[検証]参照)


↑は存在しないです。
prototypeに設定したプロパティはインスタンス固有の物にはならないですよ。


----------------
- yo

youich
Åê¹ÆNo.3596
投稿日時: 2004-2-8 14:06
職人
居住地: kobe
投稿: 349
使用環境:
Tiger
Re: クラス内の変数について
引用:

--------
//MyClass2.as
class MyClass2 {
function method(param1, param2):Void{
var param1:String;
var param2:Number
trace("MyClass2=" + param1 + "," + param2);
}
}


これは、同じスコープに同じ名前の変数の再定義になるから、普通だめでしょう。。
というか、これが通るというのはバグじゃないかなぁ?



あら、最新のポストにもレスしたけど消えたかな??


----------------
- yo

youich
Åê¹ÆNo.3597
投稿日時: 2004-2-8 15:54
職人
居住地: kobe
投稿: 349
使用環境:
Tiger
Re: クラス内の変数について
引用:
[まとめ]
---------------------------------------------------------------------------
'protoProp'と'instanceProp1'の違いを図式化(データフロー)
※[デー燭亮詑],/ポインタ/,(処理)のように書いてます。

●protoProp(コンストラクタ関数内で「設定なし」の場合)
[Test.prototype.protoProp //"prototype"]

┃  ↓(var instance1:Test=new Test("test1");)
┠←→/instance1.__proto__.protoProp/→(copy: instance1.protoProp=Test.prototype.protoProp)→[instance1.protoProp //"prototype"]

copyじゃなくてTest.prototype.protoPropを参照してるだけですよ。

引用:

●instanceProp1(コンストラクタ関数内で「設定あり」場合)
[Test.prototype.instanceProp1 //"instance"]

┃  ↓(var instance1:Test=new Test("test1");)
┃                   └→(set: instance1.instanceProp1="test1")→[instance1.instanceProp1 //"test1"]
┃   
┠←→/instance1.__proto__.instanceProp1/

newした時にはinstance1.instanceProp1と
instance1.__proto__.instancePrpo1が存在しているという意味ですよね。
それでいいと思います。

引用:

上記の考え方…間違ってると思うので指摘していただけると非常に助かります。
どうしても[FN0310006]クラスの作成と使用に掲載されているmyListの振る舞いが理解できなくて困ってます。

例えば
a1 = [1,2,3];
a2 = a1;
a2[0] = 'xxx';
trace(a1); // xxx,2,3
となるのが理解できないということでしょうか?

それ以外はmyListの振る舞いと他のprototypeに設定されたプロパティとの違いはないですよ。


----------------
- yo

takiguchi
Åê¹ÆNo.3601
投稿日時: 2004-2-8 21:45
半人前
居住地: 東京
投稿: 38
使用環境:
Win2K,FlashMX2004Pro7.0.1
Re: クラス内の変数について
youichさん、ありがとうございます。

引用:
例えば
a1 = [1,2,3];
a2 = a1;
a2[0] = 'xxx';
trace(a1); // xxx,2,3
となるのが理解できないということでしょうか?

うわ…さらに分からなくなりました
値型と参照型とかいうやつでしょうか?
上の場合、参照型?のような感じですけど
はやくも挫折しそうです

引用:
copyじゃなくてTest.prototype.protoPropを参照してるだけですよ。

これもなんとなくイメージが湧かないです
もうちょっと修行してから出直してきます…
野中文雄
Åê¹ÆNo.3602
投稿日時: 2004-2-8 22:09
ちょんまげら
居住地: 東京
投稿: 4531
使用環境:
CS5.5 .6.8 Vista Home Premium (SP1)
Re: クラス内の変数について
コンストラクタ関数の外で宣言したプロパティは、クラスのprototypeオブジェクトに設定されます。prototypeは、すでにご承知のとおり、Functionオブジェクトのプロパティです。クラスはfunctionとして定義しますので、自動的にprototypeオブジェクトをプロパティとしてもつ訳です。クラスに定義したメソッドも、このprototypeに設定されます。

コンストラクタをnew演算子で呼出してクラスのインスタンスを作成すると、インスタンスには__proto__プロパティがこれも自動的に設定されます。__proto__プロパティは、インスタンスを作成したクラスのprototypeを参照します。

オブジェクトインスタンスのプロパティを調べたり、そのメソッドのfunctionブロック内で識別子を参照すると、インスタンス自身がそのプロパティをもたないときは__proto__プロパティの参照をたどってクラスのprototype内を探します。そのクラスがさらにスーパークラスを継承している場合には、prototypeオブジェクトが__proto__プロパティをもっているので、さらにその参照をたどることになります。
// フレームアクション
my_array = new Array();
trace(my_array.__proto__ === Array.prototype);  // 出力: true
trace(Array.prototype.__proto__ === Object.prototype);  // 出力: true
trace(my_array.__proto__.__proto__ === Object.prototype);  // 出力: true
trace(Object.prototype.__proto__);  // 出力: undefined
trace(my_array.__proto__.__proto__._proto__);  // 出力: undefined

クラスのprototypeに設定されたプロパティやメソッドは、クラスに対してメモリされます。インスタンスを作成しても、それらがコピーされるのではなく、__proto__プロパティを通じて参照しているにすぎません。したがって、インスタンスに同名のプロパティを設定すれば、その値が参照されて、prototypeのプロパティは隠されてしまうことになります。しかし、prototypeのプロパティが失われる訳ではありません。インスタンスのプロパティを削除すれば、再度参照することが可能です。
// ActionScript 2.0クラス定義ファイル: MyClass.as
class MyClass extends MovieClip {
	var myNumber:Number = 0;
	var my_array:Array = [0, 1, 2];
}

// SWF: MyClass.asと同階層
// フレームアクション
var myObject:MyClass = new MyClass();
trace(myObject.myNumber);  // 出力: 0
myObject.myNumber = 100;
trace(myObject.myNumber);  // 出力: 100
trace(MyClass.prototype.myNumber);  // 出力: 0
trace(myObject.__proto__.myNumber);  // 出力: 0
delete myObject.myNumber;
trace(myObject.myNumber);  // 出力: 0

プロパティに配列を設定した場合も、とくに異なる点はありません。ただ、配列を変数(プロパティ)に代入すると値をコピーせずに、メモリのアドレスポインタ(メモリされている場所)を参照します。したがって、その配列に対する操作は、prototypeに設定した配列そのものの内容を変更することになるという性質の違いがあります。
// フレームアクション
var myObject1:MyClass = new MyClass();
trace(myObject1.my_array);  // 出力: 0,1,2
var myObject2:MyClass = new MyClass();
trace(myObject2.my_array);  // 出力: 0,1,2
myObject1.my_array[0] = 100;
trace(myObject2.my_array);  // 出力: 100,1,2
myObject1.my_array = [3, 4, 5];
trace(myObject1.my_array);  // 出力: 3,4,5
trace(myObject2.my_array);  // 出力: 100,1,2
delete myObject1.my_array;
trace(myObject1.my_array);  // 出力: 100,1,2

配列は、「参照型」のデータだからです。
引用:
takiguchiさんは書きました:
値型と参照型とかいうやつでしょうか?
上の場合、参照型?のような感じですけど


----------------
 

youich
Åê¹ÆNo.3612
投稿日時: 2004-2-9 3:15
職人
居住地: kobe
投稿: 349
使用環境:
Tiger
Re: クラス内の変数について
引用:


うわ…さらに分からなくなりました
値型と参照型とかいうやつでしょうか?
上の場合、参照型?のような感じですけど
はやくも挫折しそうです

野中さんが解説されてるのにいまさらなんですが(^^l
あるところに小学校があって、そこの1年3組のことを
Aさんは
「息子のクラス」
Bさんは
「娘のクラス」
と呼んでいるとします。

//
A.息子クラス=1年3組;
B.娘クラス =1年3組;
//

ここでAさんは息子のクラスに転校生が一人入ってきた事を聞きました。
//
A.息子クラス.転校生一人入る;
//

するとBさんの娘のクラスも人数が一人増えてしまっている。
オブジェクトや配列を参照しているというのもAさんやBさんが
同じ1年3組のことを「息子のクラス」、「娘のクラス」等と呼んでいるのと同じようなことです。。。
こんな説明じゃだめすか?(^^l

後は、protoypeや__proto__についての関係なんですが、
ASには__resolveという、そのオブジェクトに存在しないプロパティを
呼び出そうとしたときに呼び出されるメソッドがあります。

obj = new Object();
obj.__resolve = function(mes){
	trace(mes);
}
obj.unknownProperty();
//unknownProperty

これを使って考えると、もし?かしたらprototypeや__proto__の関係が
すんなり解るかもしれません、ややこしそうなら飛ばして下さい。

//ProtoExample.as
dynamic class ProtoExample{
    //__proto__をシュミレートするObject _proto
    var _proto:Object;
    
    function ProtoExample(proto:Object){
        _proto = proto;
    }
    
    //もしProtoExampleのインスタンスに無いプロパティが呼び出されたら呼ばれる
    function __resolve(prop:String){
    
    //引数にはいってきたものと同名のプロパティを_protoから探す
        var f = _proto[prop];
        
    //それがFunctionなら関数として返す。
        if( typeof f== "Function")
            return f.apply(this,arguments);
        
        return f;
    }
}
//example:
PROTOTYPE = new Object();
PROTOTYPE.prop = "prototypeProperty";
PROTOTYPE.datas = [1,2,3,4,5];

var obj1:ProtoExample = new ProtoExample(PROTOTYPE);
var obj2:ProtoExample = new ProtoExample(PROTOTYPE);


trace([obj1.prop,obj2.prop]);

//ex:obj1.prop = "instanceProperty";
obj1.prop = "instanceProperty";
trace([obj1.prop,obj2.prop]);

//ex: obj1.__proto__.prop = "OOps...";
obj1._proto.prop = "OOps...";
trace([obj1.prop,obj2.prop]);


trace([obj1.datas,obj2.datas]);
obj1.datas[0] = "X";
trace([obj1.datas,obj2.datas]);


----------------
- yo

takiguchi
Åê¹ÆNo.3626
投稿日時: 2004-2-9 21:32
半人前
居住地: 東京
投稿: 38
使用環境:
Win2K,FlashMX2004Pro7.0.1
Re: クラス内の変数について
(2004/2/10 修正)
以前の私の書き込みは、無駄が多くて見難かったため、
無駄を省きました…大掃除です。ついでにおさらいしてみました。
prototype,__proto__については自分が分かる範囲で修正しました。

非常に細かい事だと思いますが、コンパイルでエラーにならない潜在的なバグを
減らしたかったため、言語仕様的な本質についてちゃんと理解しておきたかったから
投稿させて頂きました。色々と教えてくださった野中さん、youichさんには感謝しております。

[おさらい]

■コンフリクト
特に気にする必要なし。
但し、メソッド内でインスタンスメンバを参照する場合は'this'を
クラス('static')メンバを参照する場合は'クラス名'をターゲットに指定するようにすると
不慮のスコープミスは防げると思われる。

■ActionScript 2.0の厳密な型指定
varステートメントによる変数の型指定は、自己申告であって、実際の変数の型はそれと異なる場合もある。
逆に変数の厳密な型指定(自己申告)をしなくても、実際の型というものは存在する。
(超?高級言語の仕様的な部分なのかも)

代入互換(コンパイラでエラーにならない代入)は…

●型指定なし変数 = 何でもOK;
●型指定あり変数 = 型指定なし変数;
●型指定ありA型変数 = A(B型); //無理やり型変換(キャスト) インターフェースの型等
●型指定ありA型変数 = B型; //A型がB型のスーパークラス
●型指定ありA型変数 = A型;

あとは、変数ごとに「専用の箱」が用意される「基本型」と、
一つの箱が用意されて、変数ごとにその箱を開ける「鍵」が渡されるような「参照型」
の違いがあるので注意!(これから勉強)

「参照型」はオブジェクトデータ型とも呼ばれるみたいでArray型とかObject型が
それに当たるみたい。たぶん、これらの型はメモリを大量に消費する可能性があるため、
変数ごとに専用の特大な箱を用意してたら、すぐ一杯になっちゃうからだと思う。

ちなみに、引数の型を指定する時は下記のように書いちゃダメ!
エラーにならないのはバグかもしれないし、型指定の観点からは無意味です。
---------------------------------------------------------------------
//MyClass2.as
class MyClass2 {
    function method(param1, param2):Void {
        var param1:String;
        var param2:Number;
        trace("param1:"+param1+", param2:"+param2);
    }
}
---------------------------------------------------------------------
//MyClass2a.as
class MyClass2a {
    function method(param1:String, param2:Number):Void{
        var param1:String=new String();
        var param2:Number=new Number();
        trace("param1:"+param1+", param2:"+param2);
    }
}
---------------------------------------------------------------------


■オーバーロード(同名の異なるメソッドを定義)
無理!
それに近いことをするなら引数の型を指定せずに(もしくはObject型)、
引数を素通りにさせて、メソッド内で条件分岐する。

■prototype,__proto__
難しいので、今勉強中!
youich
Åê¹ÆNo.3632
投稿日時: 2004-2-9 22:47
職人
居住地: kobe
投稿: 349
使用環境:
Tiger
Re: クラス内の変数について
[註2]はその通りなんですが、[註1]は微妙にこのような感じです。
引用:
[註1] コンストラクタ関数外でインライン初期化した場合について [★]

[クラス定義]
Testクラスを定義するということは、Testフォルダーを作りその中にprototypeフォルダーを作りそして、
その中にファイルprotoPropやinstancePropを作ることになります。

../Test/prototype/protoProp
../Test/prototype/instanceProp
(等々)

[インスタンス化]
そして、それのインスタンス"this"を作った時は"this"フォルダーが作られ、
その下に../Test/prototypeフォルダーのショートカットが作られます。

../this/prototype
そして、そのショートカットは__proto__とリネームされます。
../this/__proto__

引用:
[註2] instanceProp2を コンストラクタ関数内で初期化した場合 [★]

これはおっしゃる通りですね。
../this/instanceProp2
../this/__proto__/
(等々)


----------------
- yo

takiguchi
Åê¹ÆNo.3635
投稿日時: 2004-2-10 0:17
半人前
居住地: 東京
投稿: 38
使用環境:
Win2K,FlashMX2004Pro7.0.1
Re: クラス内の変数について
youichさん、ありがとうございます。

引用:
[クラス定義]
Testクラスを定義するということは、Testフォルダーを作りその中にprototypeフォルダーを作りそして、
その中にファイルprotoPropやinstancePropを作ることになります。

../Test/prototype/protoProp
../Test/prototype/instanceProp
(等々)

[インスタンス化]
そして、それのインスタンス"this"を作った時は"this"フォルダーが作られ、
その下に../Test/prototypeフォルダーのショートカットが作られます。

../this/prototype
そして、そのショートカットは__proto__とリネームされます。
../this/__proto__

おお!…明日にでも早速修正しておきます。
あ!自分の頭の中も忘れずに軌道修正しておかないと…
一人で「こんな感じかな?」…あ!やっぱり違う!
「ということはこんな感じかな?」
みたいに自問自答していると、どんどん不安になって
きちゃうんですけど、間違いを指摘していただけると
スッキリした気分なります。
出口が見えかけてきました
本当に感謝です。
« 1 (2) 3 »
スレッド表示 | 新しいものから 前のトピック | 次のトピック | トップ

投稿するにはまず登録を
 
Copyright (C) 2003 FLASH-japan. All rights reserved.
Powered by Xoops