関数について(Function)
・ | Function クラスについて |
・ | 関数を作成する |
・ | Function クラスのプロパティについて |
・ | Function クラスのメソッドについて |
・ | クロージャについて |
・ | コンストラクタ関数について |
・ | プロトタイプについて |
Function クラスについて
■Function クラスについて
Function クラスは、関数用のクラスです。
■関数とは?
関数は、汎用的に利用できる処理を、1つのモジュールとしてまとめたものです。
任意の式や文で構成された、命令群です。
■関数の構文
引数と呼ばれる、複数のデータを受け取る事ができます。
関数の中の命令群が最後まで実行されると、戻り値と呼ばれる1つの結果を返す事ができます。
関数宣言の構文
function 関数名 ( 引数 ){
命令文;
命令文;
命令文;
return 戻り値;
}
■任意の関数を実行する
任意の関数を実行するには、関数呼び出し演算子 ( ) を使用します。
関数呼び出しの構文
戻り値 = 関数名 ( 引数 );
丸括弧 ( ) の中には、引数を指定することができます。
引数から複数のデータを渡したい場合、カンマ , で区切ります。
引数に指定するデータは、関数ごとに仕様が異なります。
MathAdd という名前の関数を宣言し、実行する
// ------------------------------------------------------------
// MathAdd という名前の関数を宣言する
// ------------------------------------------------------------
function MathAdd ( a1 , a2 ){
// 第01引数と第02引数で渡された数値を合計し、結果を返す
return a1 + a2;
}
// ------------------------------------------------------------
// MathAdd という関数を実行する。(第01引数に 5、第02引数に 9 を指定し、結果を得る)
// ------------------------------------------------------------
var total = MathAdd( 5 , 9 );
// 出力テスト
trace(total); // 14
関数を作成する
■function 演算子を使用して、関数を宣言する
■関数を宣言する
関数を宣言するには、function 演算子を使用します。
記述例です。
関数を宣言する
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (argument1 , argument2){
var v = argument1 + argument2;
return v;
}
// ------------------------------------------------------------
// MyFunc という関数を実行して、結果を得る
// ------------------------------------------------------------
var result = MyFunc(1,2);
■関数オブジェクトにアクセスする
宣言した関数の名前を使用すると、Function オブジェクトにアクセスする事ができます。
関数を宣言する
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (argument1 , argument2){
var v = argument1 + argument2;
return v;
}
// ------------------------------------------------------------
// 関数オブジェクトを取得する
// ------------------------------------------------------------
var func_obj = MyFunc;
// 出力テスト
trace(func_obj);
■グローバルな関数宣言について
グローバルな環境(すべてのスコープの外側)で関数を宣言した場合、グローバルな関数宣言となります。
グローバルな関数宣言は、静的な関数として機能します。
■ローカルな関数宣言について
関数宣言は、任意の関数の中にも記述する事ができます。
ローカルな環境(任意の関数内)で関数を宣言した場合、ローカルな関数宣言となります。
ローカルな関数宣言は、動的な関数として機能します。(静的な関数ではありません)
■関数宣言の評価タイミングについて
関数宣言は、プログラムが順番に実行されるよりも先に評価されます。
よって関数宣言は、スコープ内の好きな場所に記述する事ができます。
■グローバルな関数宣言の評価タイミングについて
グローバルな関数宣言の場合、プログラムの実行が開始される前に、関数宣言が評価されます。
プログラムの何処からでも、グローバルな関数オブジェクトにアクセスする事ができます。
グローバルな関数宣言は、関数宣言をプログラムの後方に記述しても動作する
// ------------------------------------------------------------
// 各関数を実行して、結果を得る(グローバルな関数宣言は、関数宣言をプログラムの後方に記述しても動作する)
// ------------------------------------------------------------
var a = MyFunc_A(1,2);
var b = MyFunc_B(6,5);
var c = MyFunc_C(3,4);
// 出力テスト
trace(a); // 3
trace(b); // 1
trace(c); // 12
// ------------------------------------------------------------
// MyFunc_A という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc_A (argument1 , argument2){
var v = argument1 + argument2;
return v;
}
// ------------------------------------------------------------
// MyFunc_B という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc_B (argument1 , argument2){
var v = argument1 - argument2;
return v;
}
// ------------------------------------------------------------
// MyFunc_C という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc_C (argument1 , argument2){
var v = argument1 * argument2;
return v;
}
■ローカルな関数宣言の評価タイミングについて
ローカルな関数宣言の場合、任意の関数スコープに入った瞬間に、スコープ内の関数宣言が評価されます。
関数スコープに入るたびに、新しい関数オブジェクトが生成されます。
クロージャについては、こちらで解説しています。
ローカルな関数宣言を行った場合、ローカル関数は動的に生成される
// ------------------------------------------------------------
// MyFunc_G という名前の関数を宣言する(グローバルな関数宣言)
// ------------------------------------------------------------
function MyFunc_G (argument){
// ------------------------------------------------------------
// ローカル変数
// ------------------------------------------------------------
var _variable_ = argument;
// ------------------------------------------------------------
// MyFunc_L という名前の関数を宣言する(ローカルな関数宣言)
// ------------------------------------------------------------
function MyFunc_L (){
return _variable_;
}
// ------------------------------------------------------------
// ローカルな関数オブジェクトを返す
// ------------------------------------------------------------
return MyFunc_L;
}
// ------------------------------------------------------------
// グローバルな関数を実行して、ローカルな関数オブジェクトを取得する
// ------------------------------------------------------------
var func_obj0 = MyFunc_G("テスト1");
var func_obj1 = MyFunc_G("テスト2");
// ------------------------------------------------------------
// ローカルな関数オブジェクトを実行する
// ------------------------------------------------------------
trace(func_obj0()); // "テスト1"
trace(func_obj1()); // "テスト2"
// ------------------------------------------------------------
// ローカルな関数オブジェクト同士を比較しても一致しない(新しく関数オブジェクトが生成されているため)
// ------------------------------------------------------------
trace(func_obj0 == func_obj1); // false
■function 演算子を使用して、関数を動的に作成する
■関数を動的に生成する
関数を動的に生成するには、function 演算子を使用します。
この書式を、関数リテラルといいます。
関数リテラルの構文
var 変数 = function ( 引数 ){
命令文;
命令文;
命令文;
return 戻り値;
};
ActionScript 1.0 ~ 2.0 では、関数名を指定する事はできません。
関数リテラルは、匿名関数、無名関数とも呼ばれます。
使用例です。
関数オブジェクトを動的に生成する
// ------------------------------------------------------------
// 関数オブジェクトを動的に生成して、変数に格納する
// ------------------------------------------------------------
var func_obj = function (argument1 , argument2){
var v = argument1 + argument2;
return v;
}
// ------------------------------------------------------------
// 関数オブジェクトを実行して、結果を得る
// ------------------------------------------------------------
var result = func_obj(1,2);
■関数リテラルの評価タイミングについて
関数宣言と違って、関数リテラルが、先に評価される事はありません。
プログラムが上から順番に実行され、関数リテラルまで到達した時点で、初めて関数オブジェクトが生成されます。
すべての関数リテラルは、動的な関数として機能します。
■匿名関数を即時実行する
匿名関数は、即時実行する事ができます。
匿名関数の即時実行は、スコープとして機能するため重要です。
Function.call() メソッドを使った、匿名関数の即時実行は、Flash 6 以降から可能です。
クロージャについては、こちらで解説しています。
匿名関数を即時実行する
// ------------------------------------------------------------
// 匿名関数を即時実行する(スコープとして機能する)
// ------------------------------------------------------------
(function (){
// ローカル変数を用意する
var local_a = 123;
var local_b = "あいうえお";
// 出力テスト
trace(local_a);
trace(local_b);
}).call();
// ------------------------------------------------------------
// アクセステスト
// ------------------------------------------------------------
// ×関数スコープの外からローカル変数にアクセスできない
trace(local_a);
trace(local_b);
Function クラスのプロパティについて
■Arguments オブジェクトについて
任意の関数内では、Arguments オブジェクトにアクセスする事ができます。
Arguments オブジェクトを取得するには、任意の関数内で、arguments 変数を使用します。
関数内で、Arguments オブジェクトを取得する
// 匿名関数を即時実行する
(function (){
// 出力テスト
trace(arguments);
}).call();
■Arguments オブジェクトのプロパティ一覧
Arguments オブジェクトには、以下のプロパティがあります。
プロパティ名 | 型 | 説明 |
length | Number | 引数から渡されたデータの総数を取得する。 |
callee | Function | 自身の関数オブジェクトを取得する。 |
caller | Function | 自身の関数の実行主となる Function オブジェクトを取得する。(Flash 6 以降) |
■Arguments オブジェクトから、引数から渡されたデータを取得する
Arguments オブジェクトは、配列のように中身を取り出せます。
Arguments オブジェクトの中には、引数から渡されたデータが格納されています。
引数から渡されたデータの総数を取得するには、length プロパティを使用します。
可変引数に対応したい場合に利用します。
Arguments オブジェクトを使って、引数から渡されたすべてのデータを順番に取得する
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (){
// ------------------------------------------------------------
// 引数の総数を取得する
// ------------------------------------------------------------
var num = arguments.length;
// ------------------------------------------------------------
// 引数から渡されたすべてのデータを順番に取得する
// ------------------------------------------------------------
var i;
for(i=0;i < num;i++){
// 引数から渡されたデータを取得する
var data = arguments[i];
trace("id:" + i + " data:" + data);
}
}
// ------------------------------------------------------------
// MyFunc という関数を実行する
// ------------------------------------------------------------
MyFunc( false , 123 , "abc" , [0,1,2] , {a:0,b:1,c:2} );
■callee プロパティ
関数内から、自身の関数オブジェクトを取得するには、callee プロパティを使用します。
自身の関数オブジェクトを取得する(関数宣言内)
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (){
// 自身の関数オブジェクトを取得する
var func_obj = arguments.callee;
// 一致するか調べる
trace(func_obj == MyFunc); // true
}
// ------------------------------------------------------------
// MyFunc という関数を実行する
// ------------------------------------------------------------
MyFunc();
自身の関数オブジェクトを取得する(関数リテラル内)
// ------------------------------------------------------------
// 関数を動的に作成し、変数に格納する
// ------------------------------------------------------------
var my_func = function (){
// 自身の関数オブジェクトを取得する
var func_obj = arguments.callee;
// 一致するか調べる
trace(func_obj == my_func); // true
};
// ------------------------------------------------------------
// 関数を実行する
// ------------------------------------------------------------
my_func();
Function クラスのメソッドについて
■Function クラスのメソッド一覧
Function クラスには、以下のメソッドがあります。(一部抜粋)
■ apply() メソッド (Flash 6 以降)
関数を実行するには、apply() メソッドを使用します。
関数内で this 演算子に該当するオブジェクトを、外部から指定することができます。
関数に渡す引数は、配列を使って指定します。
Function.apply ( this , [ 引数 ] ) :*
第01引数(略可) | Object | 関数内で this 演算子に該当するオブジェクトを指定。null を指定した場合デフォルトの動作となる。 |
第02引数(略可) | Array | 引数から渡すデータを配列に格納して指定。 |
戻り値 | * | 実行した関数の戻り値が得られる |
apply() メソッドを使って、関数を実行する
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (argument1,argument2,argument3){
// 出力テスト
trace(this);
return argument1 + argument2 + argument3;
}
// ------------------------------------------------------------
// 関数オブジェクトを取得する
// ------------------------------------------------------------
var func_obj = MyFunc;
// ------------------------------------------------------------
// 関数呼び出し演算子を使って、関数を実行する
// ------------------------------------------------------------
var result = func_obj(7,8,9);
// ------------------------------------------------------------
// apply() メソッドを使って、関数を実行する
// ------------------------------------------------------------
var obj = new Object();
var result = func_obj.apply(obj,[7,8,9]);
■ call() メソッド (Flash 6 以降)
関数を実行するには、call() メソッドを使用します。
関数内で this 演算子に該当するオブジェクトを、外部から指定することができます。
関数に渡す引数は、可変引数を使って指定します。
Function.call ( this , ... ) :*
第01引数(略可) | Object | 関数内で this 演算子に該当するオブジェクトを指定。null を指定した場合デフォルトの動作となる。 |
可変引数(略可) | * | 引数から渡すデータを順番に指定。 |
戻り値 | * | 実行した関数の戻り値が得られる |
call() メソッドを使って、関数を実行する
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (argument1,argument2,argument3){
// 出力テスト
trace(this);
return argument1 + argument2 + argument3;
}
// ------------------------------------------------------------
// 関数オブジェクトを取得する
// ------------------------------------------------------------
var func_obj = MyFunc;
// ------------------------------------------------------------
// 関数呼び出し演算子を使って、関数を実行する
// ------------------------------------------------------------
var result = func_obj(7,8,9);
// ------------------------------------------------------------
// call() メソッドを使って、関数を実行する
// ------------------------------------------------------------
var obj = new Object();
var result = func_obj.call(obj,7,8,9);
クロージャについて
■クロージャについて
■スコープとは?
スコープとは、宣言した変数や関数などに対する、アクセス可能な範囲の事です。
任意のスコープ内で、変数や関数を宣言した場合、スコープの内側から自由にアクセスできます。
しかし、スコープの外側からアクセスする事はできません。
■スコープを利用するためには?
ECMAScript では、中括弧 { } を記述しただけでは、スコープとして機能しません。
例えば、以下のソースは、スコープとして機能しません。
中括弧 { } を記述していない時と、同じ動作をします。
中括弧 { } を記述しただけでは、スコープとして機能しない
{
// 変数を宣言
var aaa = 1;
var bbb = 2;
var ccc = 3;
}
// 出力テスト(外側からアクセスできるのでスコープではない)
trace(aaa); // 1
trace(bbb); // 2
trace(ccc); // 3
■関数はスコープとして機能する
ECMAScript では、関数を利用すると、スコープとして機能します。
関数は、スコープとして機能する
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc () {
// 関数内で変数を宣言
var aaa = 1;
var bbb = 2;
var ccc = 3;
// 出力テスト(○アクセス可能)
trace(aaa); // 1
trace(bbb); // 2
trace(ccc); // 3
}
// ------------------------------------------------------------
// MyFunc 関数を実行する
// ------------------------------------------------------------
MyFunc();
// ------------------------------------------------------------
// アクセステスト(×関数スコープの外側からアクセスできない)
// ------------------------------------------------------------
trace(aaa);
trace(bbb);
trace(ccc);
■ローカル変数について
関数内で変数を宣言すると、ローカル変数を作成することができます。
通常であれば、ローカル変数は、スコープの外に出ると消滅します。
関数の中で変数を宣言すると、ローカル変数となる
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc() {
// ローカル変数を宣言 (関数内で変数を宣言しているのでローカル変数となる)
var local_val;
var local_str;
local_val = 123;
local_str = "あいうえお";
}
■ローカル関数について
任意の関数の中では、関数を宣言したり、動的に関数を作成することができます。
任意のスコープ内で作られた関数を、ローカル関数と言います。
ローカル関数の中からは、同じスコープ内とスコープの外側に存在する環境にアクセスする事ができます。
関数の中からは、同じスコープ内と、スコープの外側に存在する環境にアクセスできる
// ------------------------------------------------------------
// グローバル変数を宣言
// ------------------------------------------------------------
var global_a = "aaa";
var global_b = "bbb";
// ------------------------------------------------------------
// MyFunc_G という名前の関数を宣言する(グローバルな関数)
// ------------------------------------------------------------
function MyFunc_G() {
// ------------------------------------------------------------
// ローカル変数を宣言
// ------------------------------------------------------------
var local_a0 = "ccc";
var local_a1 = "ddd";
// ------------------------------------------------------------
// MyFunc_L という名前の関数を宣言する(関数の中で、さらに関数を宣言しているのでローカル関数となる)
// ------------------------------------------------------------
function MyFunc_L() {
// ------------------------------------------------------------
// ローカル変数を宣言
// ------------------------------------------------------------
var local_b0 = "eee";
var local_b1 = "fff";
// ------------------------------------------------------------
// アクセステスト
// ------------------------------------------------------------
// スコープの外側に存在する環境にアクセスできる
trace(global_a); // "aaa"
trace(global_b); // "bbb"
trace(local_a0); // "ccc"
trace(local_a1); // "ddd"
// 同じスコープ内の環境にアクセスできる
trace(local_b0); // "eee"
trace(local_b1); // "fff"
}
// ------------------------------------------------------------
// MyFunc_L 関数を実行する
// ------------------------------------------------------------
MyFunc_L();
}
// ------------------------------------------------------------
// MyFunc_G 関数を実行する
// ------------------------------------------------------------
MyFunc_G();
■ローカル関数をスコープの外側に持ち出した場合
ローカル関数は、オブジェクトの一種なので、スコープの外に持ち出すことができます。
スコープの内側で作成した関数オブジェクトを、スコープの外側から実行します。
この場合、スコープ内の環境は消滅していません。
関数オブジェクトが消滅しない限り、スコープ内の環境も生存し続けます。
スコープの中で作成した関数オブジェクトを、スコープの外から実行する
// ------------------------------------------------------------
// MyFunc_G という名前の関数を宣言する(グローバルな関数)
// ------------------------------------------------------------
function MyFunc_G() {
// ------------------------------------------------------------
// ローカル変数を宣言
// ------------------------------------------------------------
var local_a = "aaa";
var local_b = "bbb";
// ------------------------------------------------------------
// MyFunc_L という名前の関数を宣言する(ローカル関数)
// ------------------------------------------------------------
function MyFunc_L() {
// アクセステスト
trace(local_a); // "aaa"
trace(local_b); // "bbb"
}
// ------------------------------------------------------------
// MyFunc_L 関数オブジェクトを返す
// ------------------------------------------------------------
return MyFunc_L;
}
// ------------------------------------------------------------
// MyFunc_G 関数を実行して、新しい関数オブジェクトを取得する
// ------------------------------------------------------------
var func_obj = MyFunc_G();
// ------------------------------------------------------------
// 関数オブジェクトを実行する(MyFunc_G 関数のスコープ内の環境は、生存し続けている)
// ------------------------------------------------------------
func_obj();
■クロージャとは?
任意の関数が生存していれば、その関数内からアクセスできるすべての環境も生存し続けます。
この仕様を、クロージャといいます。
引数の変数も、ローカル変数として扱われるため、生存し続けます。
引数の変数もローカル変数なので、生存し続ける
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する(グローバルな関数)
// ------------------------------------------------------------
function MyFunc( name ){
// ------------------------------------------------------------
// ローカル変数を宣言
// ------------------------------------------------------------
var count = 0;
// ------------------------------------------------------------
// 関数オブジェクトを動的に作成して返す
// ------------------------------------------------------------
return function () {
// 出力テスト
trace("name:" + name + " count:" + count);
// カウント
count++;
};
}
// ------------------------------------------------------------
// MyFunc 関数を実行して、新しく関数を生成する
// ------------------------------------------------------------
var func_obj0 = MyFunc("テスト1");
var func_obj1 = MyFunc("テスト2");
var func_obj2 = MyFunc("テスト3");
// ------------------------------------------------------------
// 実行テスト
// ------------------------------------------------------------
func_obj0(); // name:"テスト1" count:0
func_obj1(); // name:"テスト2" count:0
func_obj2(); // name:"テスト3" count:0
func_obj2(); // name:"テスト3" count:1
func_obj2(); // name:"テスト3" count:2
func_obj2(); // name:"テスト3" count:3
func_obj1(); // name:"テスト2" count:1
func_obj2(); // name:"テスト3" count:4
コンストラクタ関数について
■コンストラクタ関数について
■コンストラクタ関数について
関数オブジェクトは、コンストラクタ関数としても機能します。
コンストラクタは、構築者を意味します。
コンストラクタ関数は、新しいオブジェクトを初期化する為に利用することができます。
■コンストラクタ関数を実体化する
コンストラクタ関数をインスタンス化(実体化)するには、new 演算子を使用します。
new 演算子の構文
var 変数 = new 関数オブジェクト ( 引数 );
new 演算子を使用すると、新しいオブジェクトを生成する事ができます。
コンストラクタ関数を実体化し、新しいオブジェクトを作成する
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (){
}
// ------------------------------------------------------------
// コンストラクタ関数を実体化し、新しいオブジェクトを作成する
// ------------------------------------------------------------
var obj = new MyFunc();
// 出力テスト
trace(obj);
コンストラクタ関数を実体化し、新しいオブジェクトを作成する
// ------------------------------------------------------------
// 関数リテラルを使って、関数を動的に作成する
// ------------------------------------------------------------
var func_obj = function (){
};
// ------------------------------------------------------------
// コンストラクタ関数を実体化し、新しいオブジェクトを作成する
// ------------------------------------------------------------
var obj = new func_obj();
// 出力テスト
trace(obj);
■「関数呼び出し演算子」と「new 演算子」の違いについて
関数内の、this 演算子に該当するオブジェクトが変化します。
new 演算子を使用した場合、this 演算子は、生成される新しいオブジェクトを指します。
呼び出した関数内の this の違いを確認する
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (){
// 出力テスト
trace( this );
}
// ------------------------------------------------------------
// 関数呼び出し演算子を使用する(this 演算子は「_root オブジェクト」を指す)
// ------------------------------------------------------------
MyFunc();
// ------------------------------------------------------------
// new 演算子を使用する(this 演算子は「生成される新しいオブジェクト」を指す)
// ------------------------------------------------------------
var obj = new MyFunc();
■コンストラクタ関数内の初期化方法について
this 演算子から、生成される新しいオブジェクトを取得する事ができます。
このオブジェクトに、好きなプロパティを追加していきます。
コンストラクタ関数内で、プロパティを追加する
// ------------------------------------------------------------
// MyClass という名前の関数を宣言する
// ------------------------------------------------------------
function MyClass (){
// プロパティを追加する
this.aaa = "a";
this.bbb = "b";
this.ccc = "c";
}
// ------------------------------------------------------------
// MyClass オブジェクトを作成
// ------------------------------------------------------------
var obj = new MyClass();
// 出力テスト
trace(obj); // aaa:"a" , bbb:"b" , ccc:"c"
■コンストラクタ関数の戻り値について
コンストラクタ関数内では、戻り値を指定する必要はありません。
this 以外の値を返してしまうと、コンストラクタ関数として機能しなくなります。
■パブリックなプロパティを追加する(公開プロパティ)
プロパティを追加して、データを格納した場合、パブリックなプロパティとなります。
パブリックなプロパティを追加する
// ------------------------------------------------------------
// MyClass という名前の関数を宣言する
// ------------------------------------------------------------
function MyClass (){
// ------------------------------------------------------------
// パブリックなプロパティ(公開プロパティ)
// ------------------------------------------------------------
this.aaa = "a";
this.bbb = "b";
}
// ------------------------------------------------------------
// MyClass オブジェクトを作成
// ------------------------------------------------------------
var obj = new MyClass();
// ------------------------------------------------------------
// 出力テスト
// ------------------------------------------------------------
trace(obj.aaa); // "a"
trace(obj.bbb); // "b"
■パブリックなメソッドを追加する(公開メソッド)
プロパティを追加して、関数を格納した場合、パブリックなメソッドとなります。
パブリックなメソッドを追加する
// ------------------------------------------------------------
// MyClass という名前の関数を宣言する
// ------------------------------------------------------------
function MyClass (){
// ------------------------------------------------------------
// パブリックなメソッド(公開メソッド)
// ------------------------------------------------------------
this.func0 = function (){
trace("func0 メソッドが実行された");
};
// ------------------------------------------------------------
// パブリックなメソッド(公開メソッド)
// ------------------------------------------------------------
this.func1 = function (){
trace("func1 メソッドが実行された");
};
}
// ------------------------------------------------------------
// MyClass オブジェクトを作成
// ------------------------------------------------------------
var obj = new MyClass();
// ------------------------------------------------------------
// 実行テスト
// ------------------------------------------------------------
obj.func0();
obj.func1();
■データの隠匿について
コンストラクタ関数内で、変数を宣言した場合、ローカル変数となります。
関数スコープの外側から、ローカル変数にアクセスする事はできません。
通常であれば、コンストラクタ関数を抜けると、ローカル変数は消滅してしまいます。
しかし、パブリックなメソッドを用意すれば、ローカル変数を生存させ続ける事ができます。
ローカル変数と、公開メソッドを組み合わせると、データを隠匿する事ができます。
クロージャについては、こちらで解説しています。
ローカル変数と、公開メソッドを組み合わせてデータを隠匿する
// ------------------------------------------------------------
// MyClass という名前の関数を宣言する
// ------------------------------------------------------------
function MyClass (){
// ------------------------------------------------------------
// ローカル変数を宣言(プライベートな変数)
// ------------------------------------------------------------
var _name;
var _value;
// ------------------------------------------------------------
// 名前を取得するメソッド
// ------------------------------------------------------------
this.getName = function (){
return _name;
};
// ------------------------------------------------------------
// 名前をセットするメソッド
// ------------------------------------------------------------
this.setName = function (v){
_name = v;
};
// ------------------------------------------------------------
// 値を取得するメソッド
// ------------------------------------------------------------
this.getValue = function (){
return _value;
};
// ------------------------------------------------------------
// 値をセットするメソッド
// ------------------------------------------------------------
this.setValue = function (v){
_value = v;
};
// ------------------------------------------------------------
// 初期化処理
// ------------------------------------------------------------
(function (){
_name = "元の名前";
_value = 123;
}).call(this);
}
// ------------------------------------------------------------
// MyClass オブジェクトを作成
// ------------------------------------------------------------
var obj = new MyClass();
// ------------------------------------------------------------
// 読み取りテスト
// ------------------------------------------------------------
trace(obj.getName()); // "元の名前"
trace(obj.getValue()); // 123
// ------------------------------------------------------------
// 書き込みテスト
// ------------------------------------------------------------
obj.setName("新しい名前");
obj.setValue(456);
// ------------------------------------------------------------
// 読み取りテスト
// ------------------------------------------------------------
trace(obj.getName()); // "新しい名前"
trace(obj.getValue()); // 456
プロトタイプについて
■プロトタイプベースについて
■プロトタイプベースについて
ECMAScript は、プロトタイプベース(インスタンスベース)の言語です。
プロトタイプは、実体化済みのオブジェクト(インスタンス)です。
実体化済みであるオブジェクトをベースにして、新しいオブジェクトを生成できます。
■クラスベースについて
クラスベースとは、プロトタイプベースの対となる用語です。
静的な定義(未実体)であるクラスをベースにして、新しいオブジェクトを作成できます。
ActionScript2.0 では、クラスを使用した、クラスベースなコードを書く事もできます。
■「コンストラクタ関数」と「プロトタイプ」の関係について
■新しいインスタンスを生成する
new 演算子を使って、コンストラクタ関数を、インスタンス化(実体化)する事ができます。
実体化すると、新しいオブジェクトを作成する事ができます。
新しいオブジェクトは、インスタンス(実体)とも呼ばれます。
コンストラクタ関数については、こちらで解説しています。
コンストラクタ関数を実体化し、新しいオブジェクトを作成する
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (){
}
// ------------------------------------------------------------
// コンストラクタ関数を実体化し、新しいオブジェクトを作成する
// ------------------------------------------------------------
var obj = new MyFunc();
// 出力テスト
trace(obj);
■関数が所有するプロトタイプについて
関数は、プロトタイプと呼ばれるオブジェクトを、最初から持っています。
関数からプロトタイプを取得するには、prototype プロパティを使用します。
コンストラクタが所有する、プロトタイプオブジェクトを取得する
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (){
}
// ------------------------------------------------------------
// 関数が所有する、デフォルトのプロトタイプオブジェクトを取得する
// ------------------------------------------------------------
var prototype_obj = MyFunc.prototype;
// 出力テスト
trace(prototype_obj);
■「インスタンス」と「プロトタイプ」の関係について
■インスタンスの原型について
関数が所有していたプロトタイプは、新しいインスタンスと関連付けられます。
新しいインスタンスにとって、プロトタイプは、原型(親)となります。
■インスタンスから、プロトタイプとなるオブジェクトを取得する
__proto__ プロパティを使用します。
インスタンスのプロトタイプを確認する
// ------------------------------------------------------------
// Array コンストラクタが所有する、デフォルトのプロトタイプオブジェクトを取得する
// ------------------------------------------------------------
var prototype_obj0 = Array.prototype;
// ------------------------------------------------------------
// Array オブジェクトを作成する
// ------------------------------------------------------------
var array_obj = new Array();
// ------------------------------------------------------------
// プロトタイプ(原型)となるオブジェクトを取得する
// ------------------------------------------------------------
var prototype_obj1 = array_obj.__proto__;
// ------------------------------------------------------------
// 同一であるか確認する
// ------------------------------------------------------------
trace(prototype_obj0 === prototype_obj1); // true
■プロトタイプの共有関係について
プロトタイプは、静的な定義(未実体)ではありません。
プロトタイプは、オブジェクトであり、実体化済みのインスタンスです。
1つのプロトタイプは、複数のインスタンスから参照されます。
プロトタイプは、すべての派生オブジェクト間で共有されます。
プロトタイプは、Live な資産です。
もしプロトタイプ内を変更した場合、すべての派生オブジェクトに影響があります。
インスタンスのプロトタイプが同じであるか確認する
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (){
}
// ------------------------------------------------------------
// デフォルトのプロトタイプオブジェクトを取得する
// ------------------------------------------------------------
var prototype_obj = MyFunc.prototype;
// ------------------------------------------------------------
// コンストラクタ関数を実体化し、新しいオブジェクトを作成する
// ------------------------------------------------------------
var obj0 = new MyFunc();
var obj1 = new MyFunc();
var obj2 = new MyFunc();
// ------------------------------------------------------------
// プロトタイプ(原型)となるオブジェクトを取得する
// ------------------------------------------------------------
var prototype_obj0 = obj0.__proto__;
var prototype_obj1 = obj1.__proto__;
var prototype_obj2 = obj2.__proto__;
// ------------------------------------------------------------
// 同一であるか確認する
// ------------------------------------------------------------
trace(prototype_obj === prototype_obj0); // true
trace(prototype_obj === prototype_obj1); // true
trace(prototype_obj === prototype_obj2); // true
■「新しく生成するオブジェクト」のプロトタイプを設定する
■プロトタイプオブジェクトを変更する
プロトタイプは、別のオブジェクトに変更する事ができます。
関数の prototype プロパティに、任意のオブジェクトをセットします。
prototype プロパティの設定は、実体化よりも以前に、済ませておく必要があります。
実体化後に変更しても、生成済みのインスタンスには、反映されません。
組み込み関数の prototype プロパティは、変更する事はできません。
新しいプロトタイプオブジェクトを作成し、コンストラクタ関数に登録する
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (){
}
// ------------------------------------------------------------
// プロトタイプ用のオブジェクトを作成する
// ------------------------------------------------------------
var prototype_obj = new Object();
prototype_obj.aaa = "a";
prototype_obj.bbb = "b";
prototype_obj.ccc = "c";
// ------------------------------------------------------------
// コンストラクタ関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
// ------------------------------------------------------------
MyFunc.prototype = prototype_obj;
// ------------------------------------------------------------
// コンストラクタ関数を実体化する
// ------------------------------------------------------------
var obj = new MyFunc();
// 出力テスト
trace(obj.aaa); // "a"
trace(obj.bbb); // "b"
trace(obj.ccc); // "c"
■デフォルトのプロトタイプを拡張する
最初から存在するプロトタイプに対して、機能を追加する事もできます。
組み込み関数のプロトタイプは、変更しない方がいいでしょう。
既存のプロトタイプに対して、機能を追加する
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (){
}
// ------------------------------------------------------------
// デフォルトのプロトタイプオブジェクトにデータを追加する
// ------------------------------------------------------------
var prototype_obj = MyFunc.prototype;
prototype_obj.aaa = "a";
prototype_obj.bbb = "b";
prototype_obj.ccc = "c";
// ------------------------------------------------------------
// MyFunc オブジェクトを作成する
// ------------------------------------------------------------
var obj = new MyFunc();
// 出力テスト
trace(obj.aaa); // "a"
trace(obj.bbb); // "b"
trace(obj.ccc); // "c"
■プロトタイプチェーンについて
■プロトタイプチェーンを構築する
プロトタイプはオブジェクトなので、さらに別のプロトタイプを持つ事ができます。
プロトタイプを使って、オブジェクトを数珠つなぎのように連結する事ができます。
このような連結構造を、プロトタイプチェーンといいます。
3段のプロトタイプチェーンを構築する
// ------------------------------------------------------------
// MyFunc_A という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc_A (){
}
// ------------------------------------------------------------
// MyFunc_B という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc_B (){
}
// ------------------------------------------------------------
// MyFunc_C という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc_C (){
}
// ------------------------------------------------------------
// MyFunc_A オブジェクトを作成する(Object → MyFunc_A)
// ------------------------------------------------------------
var obj_a = new MyFunc_A();
// ------------------------------------------------------------
// MyFunc_B 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
// ------------------------------------------------------------
MyFunc_B.prototype = obj_a;
// ------------------------------------------------------------
// MyFunc_B オブジェクトを作成する(Object → MyFunc_A → MyFunc_B)
// ------------------------------------------------------------
var obj_b = new MyFunc_B();
// ------------------------------------------------------------
// MyFunc_C 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
// ------------------------------------------------------------
MyFunc_C.prototype = obj_b;
// ------------------------------------------------------------
// MyFunc_C オブジェクトを作成する(Object → MyFunc_A → MyFunc_B → MyFunc_C)
// ------------------------------------------------------------
var obj_c = new MyFunc_C();
■オブジェクト(プロトタイプチェーン)のアクセスについて
■プロパティに読み取りアクセスした場合
オブジェクトの任意のプロパティに、読み取りアクセスを試みたとします。
オブジェクトにプロパティが存在する場合、オブジェクトからデータを取得します。
存在しなかった場合、次に、プロトタイプにアクセスします。
プロトタイプにプロパティが存在する場合、プロトタイプからデータを取得します。
存在しなかった場合、さらに次のプロトタイプにアクセスします。
最終的に、プロトタイプチェーン内に存在しなかった場合、未定義となります。
プロトタイプを拡張したオブジェクトのプロパティに読み取りアクセスする
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (){
this.bbb = "b";
}
// ------------------------------------------------------------
// デフォルトのプロトタイプオブジェクトを取得する
// ------------------------------------------------------------
var prototype_obj = MyFunc.prototype;
prototype_obj.aaa = "a";
// ------------------------------------------------------------
// MyFunc オブジェクトを作成する
// ------------------------------------------------------------
var obj = new MyFunc();
// ------------------------------------------------------------
// 読み取りアクセステスト
// ------------------------------------------------------------
trace(obj.aaa); // "a"
trace(obj.bbb); // "b"
trace(obj.ccc); // undefined
プロトタイプチェーン状態にある、オブジェクトのプロパティに読み取りアクセスする
// ------------------------------------------------------------
// MyFunc_A という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc_A (){
this.aaa = "a";
}
// ------------------------------------------------------------
// MyFunc_B という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc_B (){
this.bbb = "b";
}
// ------------------------------------------------------------
// MyFunc_B 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
// ------------------------------------------------------------
MyFunc_B.prototype = new MyFunc_A();
// ------------------------------------------------------------
// MyFunc_B オブジェクトを作成する(Object → MyFunc_A → MyFunc_B)
// ------------------------------------------------------------
var obj_b = new MyFunc_B();
// ------------------------------------------------------------
// 読み取りアクセステスト
// ------------------------------------------------------------
trace(obj_b.aaa); // "a"
trace(obj_b.bbb); // "b"
trace(obj_b.ccc); // undefined
■プロパティに書き込みアクセスした場合
オブジェクトの任意のプロパティに、書き込みアクセスを試みたとします。
プロパティが存在しなかった場合、自身のオブジェクトにプロパティが追加されます。
存在する場合、自身のプロパティにデータがセットされます。
書き込みアクセスによって変化するのは、自身のオブジェクトのみです。
プロトタイプ内が、汚染する事はありません。
プロトタイプを拡張したオブジェクトのプロパティに書き込みアクセスする
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (){
}
// ------------------------------------------------------------
// デフォルトのプロトタイプオブジェクトを取得する
// ------------------------------------------------------------
var prototype_obj = MyFunc.prototype;
prototype_obj.aaa = "a";
prototype_obj.bbb = "b";
// ------------------------------------------------------------
// MyFunc オブジェクトを作成する(Object → MyFunc)
// ------------------------------------------------------------
var obj0 = new MyFunc();
var obj1 = new MyFunc();
// ------------------------------------------------------------
// 書き込みアクセステスト
// ------------------------------------------------------------
obj0.aaa = "書き込みA";
obj1.bbb = "書き込みB";
// ------------------------------------------------------------
// 出力テスト(プロトタイプオブジェクト内は変化しない)
// ------------------------------------------------------------
trace(prototype_obj.aaa); // "a"
trace(prototype_obj.bbb); // "b"
// ------------------------------------------------------------
// 出力テスト(インスタンスオブジェクト内は変化する)
// ------------------------------------------------------------
trace(obj0.aaa); // "書き込みA"
trace(obj1.aaa); // "a"
trace(obj0.bbb); // "b"
trace(obj1.bbb); // "書き込みB"
プロトタイプチェーン状態にある、オブジェクトのプロパティに書き込みアクセスする
// ------------------------------------------------------------
// MyFunc_A という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc_A (){
this.aaa = "a";
this.bbb = "b";
}
// ------------------------------------------------------------
// MyFunc_B という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc_B (){
}
// ------------------------------------------------------------
// MyFunc_A オブジェクトを作成する(Object → MyFunc_A)
// ------------------------------------------------------------
var obj_a = new MyFunc_A();
// ------------------------------------------------------------
// MyFunc_B 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
// ------------------------------------------------------------
MyFunc_B.prototype = obj_a;
// ------------------------------------------------------------
// MyFunc_B オブジェクトを作成する(Object → MyFunc_A → MyFunc_B)
// ------------------------------------------------------------
var obj_b0 = new MyFunc_B();
var obj_b1 = new MyFunc_B();
// ------------------------------------------------------------
// 書き込みアクセステスト
// ------------------------------------------------------------
obj_b0.aaa = "書き込みA";
obj_b1.bbb = "書き込みB";
// ------------------------------------------------------------
// 出力テスト(プロトタイプオブジェクト内は変化しない)
// ------------------------------------------------------------
trace(obj_a.aaa); // "a"
trace(obj_a.bbb); // "b"
// ------------------------------------------------------------
// 出力テスト(インスタンスオブジェクト内は変化する)
// ------------------------------------------------------------
trace(obj_b0.aaa); // "書き込みA"
trace(obj_b1.aaa); // "a"
trace(obj_b0.bbb); // "b"
trace(obj_b1.bbb); // "書き込みB"
■パブリックなメソッドを呼び出した場合
読み取りアクセス順は、プロパティと同じです。
プロトタイプが保有している関数オブジェクトにも、アクセスできます。
プロトタイプから供給しているメソッドを実行した場合、プロトタイプ自身のプロパティや、プロトタイプ内のローカル環境に、書き込みアクセスできます。
この場合、プロトタイプ内は汚染してしまうので、回避する必要があります。
クロージャについては、こちらで解説しています。
プロトタイプチェーン状態にある、オブジェクトのメソッドを実行する
// ------------------------------------------------------------
// MyFunc_A という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc_A (){
// ------------------------------------------------------------
// プライベートな変数
// ------------------------------------------------------------
var _local_a = "a";
// ------------------------------------------------------------
// Aからデータを取得するメソッド
// ------------------------------------------------------------
this.getA = function (){
return _local_a;
};
// ------------------------------------------------------------
// Aにデータをセットするメソッド
// ------------------------------------------------------------
this.setA = function (v){
_local_a = v;
};
}
// ------------------------------------------------------------
// MyFunc_B という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc_B (){
// ------------------------------------------------------------
// プライベートな変数
// ------------------------------------------------------------
var _local_b = "b";
// ------------------------------------------------------------
// Bからデータを取得するメソッド
// ------------------------------------------------------------
this.getB = function (){
return _local_b;
};
// ------------------------------------------------------------
// Bにデータをセットするメソッド
// ------------------------------------------------------------
this.setB = function (v){
_local_b = v;
};
}
// ------------------------------------------------------------
// MyFunc_A オブジェクトを作成する(Object → MyFunc_A)
// ------------------------------------------------------------
var obj_a = new MyFunc_A();
// ------------------------------------------------------------
// MyFunc_B 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
// ------------------------------------------------------------
MyFunc_B.prototype = obj_a;
// ------------------------------------------------------------
// MyFunc_B オブジェクトを作成する(Object → MyFunc_A → MyFunc_B)
// ------------------------------------------------------------
var obj_b0 = new MyFunc_B();
var obj_b1 = new MyFunc_B();
// ------------------------------------------------------------
// 出力テスト
// ------------------------------------------------------------
trace(obj_a.getA()); // "a"
trace(obj_b0.getA()); // "a"
trace(obj_b1.getA()); // "a"
trace(obj_b0.getB()); // "b"
trace(obj_b1.getB()); // "b"
// ------------------------------------------------------------
// 書き込みアクセステスト
// ------------------------------------------------------------
obj_b0.setA("書き込みA");
obj_b1.setB("書き込みB");
// ------------------------------------------------------------
// 出力テスト(プロトタイプから供給しているメソッドを実行すれば、プロトタイプ内を変化させる事ができる)
// ------------------------------------------------------------
trace(obj_a.getA()); // "書き込みA"
trace(obj_b0.getA()); // "書き込みA"
trace(obj_b1.getA()); // "書き込みA"
// ------------------------------------------------------------
// 出力テスト
// ------------------------------------------------------------
trace(obj_b0.getB()); // "b"
trace(obj_b1.getB()); // "書き込みB"
■プロトタイプベースの継承について
■合理的な継承を実現するには?
パブリックなメソッドは、できるだけプロトタイプ側に実装します。
プロトタイプに1つの機能を追加すれば、すべての派生オブジェクトから利用できます。
しかし、パブリックなメソッドは、プロトタイプ内が汚染する可能性があります。
プロトタイプ内が汚染しないように、注意して実装する必要があります。
■プロトタイプオブジェクトの汚染を回避する
ローカル環境に書き込みアクセスしないようにします。
プロトタイプ内で必要な変数は、すべてプロパティとして公開します。
外部からアクセスを禁止したいプロパティは、命名を工夫します。
先頭や後尾にアンダーバーを付けて、怪しげな名前にするなどの方法があります。
プロトタイプのメソッド内から、プロパティにアクセスする場合、this 演算子を使用します。
■プロトタイプベースの継承例
デフォルトのプロトタイプオブジェクトを拡張する
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (){
}
// ------------------------------------------------------------
// MyFunc のデフォルトのプロトタイプオブジェクトを拡張する
// ------------------------------------------------------------
(function(){
// ------------------------------------------------------------
// 自身のオブジェクト(MyFunc のプロトタイプオブジェクト)
// ------------------------------------------------------------
var self = MyFunc.prototype;
// ------------------------------------------------------------
// ローカルで使用する変数(プロパティとして公開)
// ------------------------------------------------------------
self._data = "初期値";
// ------------------------------------------------------------
// データを取得するメソッド
// ------------------------------------------------------------
self.getData = function (){
return this._data;
};
// ------------------------------------------------------------
// データをセットするメソッド
// ------------------------------------------------------------
self.setData = function (v){
// this 演算子を使ってプロパティにアクセスする
this._data = v;
// このようにアクセスした場合は汚染する
//self._data = v;
};
}).call(this);
// ------------------------------------------------------------
// MyFunc オブジェクトを作成する(Object → MyFunc)
// ------------------------------------------------------------
var obj0 = new MyFunc();
var obj1 = new MyFunc();
// ------------------------------------------------------------
// 出力テスト
// ------------------------------------------------------------
trace(obj0.getData()); // "初期値"
trace(obj1.getData()); // "初期値"
// ------------------------------------------------------------
// 書き込みアクセステスト
// ------------------------------------------------------------
obj0.setData("書き込み");
// ------------------------------------------------------------
// 出力テスト
// ------------------------------------------------------------
trace(obj0.getData()); // "書き込み"
trace(obj1.getData()); // "初期値"
3段のプロトタイプベースの継承を実現する
// ------------------------------------------------------------
// MyFunc_A という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc_A (){
// ------------------------------------------------------------
// 自身のオブジェクト
// ------------------------------------------------------------
var self = this;
// ------------------------------------------------------------
// ローカルで使用する変数(プロパティとして公開)
// ------------------------------------------------------------
self._local_a = "a";
// ------------------------------------------------------------
// Aからデータを取得するメソッド
// ------------------------------------------------------------
self.getA = function (){
return this._local_a;
};
// ------------------------------------------------------------
// Aにデータをセットするメソッド
// ------------------------------------------------------------
self.setA = function (v){
this._local_a = v;
};
}
// ------------------------------------------------------------
// MyFunc_B という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc_B (){
// ------------------------------------------------------------
// 自身のオブジェクト
// ------------------------------------------------------------
var self = this;
// ------------------------------------------------------------
// ローカルで使用する変数(プロパティとして公開)
// ------------------------------------------------------------
self._local_b = "b";
// ------------------------------------------------------------
// Bからデータを取得するメソッド
// ------------------------------------------------------------
self.getB = function (){
return this._local_b;
};
// ------------------------------------------------------------
// Bにデータをセットするメソッド
// ------------------------------------------------------------
self.setB = function (v){
this._local_b = v;
};
}
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (){
}
// ------------------------------------------------------------
// MyFunc_B 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
// ------------------------------------------------------------
MyFunc_B.prototype = new MyFunc_A();
// ------------------------------------------------------------
// MyFunc 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
// ------------------------------------------------------------
MyFunc.prototype = new MyFunc_B();
// ------------------------------------------------------------
// MyFunc オブジェクトを作成する(Object → MyFunc_A → MyFunc_B → MyFunc)
// ------------------------------------------------------------
var obj0 = new MyFunc();
var obj1 = new MyFunc();
// ------------------------------------------------------------
// 出力テスト
// ------------------------------------------------------------
trace(obj0.getA()); // "a"
trace(obj1.getA()); // "a"
trace(obj0.getB()); // "b"
trace(obj1.getB()); // "b"
// ------------------------------------------------------------
// 書き込みアクセステスト
// ------------------------------------------------------------
obj0.setA("書き込みA");
obj1.setB("書き込みB");
// ------------------------------------------------------------
// 出力テスト
// ------------------------------------------------------------
trace(obj0.getA()); // "書き込みA"
trace(obj1.getA()); // "a"
trace(obj0.getB()); // "b"
trace(obj1.getB()); // "書き込みB"
■クラスのような静的な継承について
プロトタイプを共有せずに、クラスのような静的な継承を実現します。
この方法は、インスタンスごとにメソッドが用意されるため、合理的ではありません。
そのかわり、カプセル化が実現できます。
1.プロトタイプを指定して、新しいオブジェクトを生成する
プロトタイプオブジェクトを指定して、新しくオブジェクトを作成する関数を用意します。
プロトタイプを指定して新しいオブジェクトを生成する関数
// ------------------------------------------------------------
// プロトタイプを指定して新しいオブジェクトを生成する関数
// ------------------------------------------------------------
function ObjectCreateByPrototype(prototype){
var f = function (){};
f.prototype = prototype;
return new f();
}
2.コンストラクタ関数を実行せずに、新しいオブジェクトを作成する
引数に、関数の prototype プロパティにあるプロトタイプオブジェクトを指定します。
すると、コンストラクタ関数を実行すること無く、オブジェクトを作成する事ができます。
これを利用すると、先にプロトタイプ用オブジェクトを用意し、後で初期化関数を実行する事ができます。
コンストラクタ関数を実行せずに、インスタンスを生成する
// ------------------------------------------------------------
// プロトタイプを指定して新しいオブジェクトを生成する関数
// ------------------------------------------------------------
function ObjectCreateByPrototype(prototype){
var f = function (){};
f.prototype = prototype;
return new f();
}
// ------------------------------------------------------------
// MyFunc という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc (){
trace("コンストラクタ関数が実行された");
}
// ------------------------------------------------------------
// コンストラクタ関数を実行せずに、MyFunc オブジェクトを作成する
// ------------------------------------------------------------
var obj = ObjectCreateByPrototype(MyFunc.prototype);
// ------------------------------------------------------------
// 出力テスト
// ------------------------------------------------------------
trace(obj instanceof MyFunc); // true
trace(obj instanceof Object); // true
3.コンストラクタ関数内で、派生元コンストラクタ関数を実行し初期化する
継承したいコンストラクタ関数内で、派生元コンストラクタ関数を実行し、初期化します。
コントラクタ関数の実行には、Function.apply() メソッドを使用するといいでしょう。
これで、new 演算子を使用するたびに、すべてのコンストラクタ関数を実行する事ができます。
プロトタイプオブジェクトは、ダミーです。変更される事はありません。
すべての初期化処理は、新しく生成されるオブジェクトに施されます。
継承したいコンストラクタ関数内で、派生元コンストラクタ関数を実行し初期化する
// ------------------------------------------------------------
// プロトタイプを指定して新しいオブジェクトを生成する関数
// ------------------------------------------------------------
function ObjectCreateByPrototype(prototype){
var f = function (){};
f.prototype = prototype;
return new f();
}
// ------------------------------------------------------------
// MyFunc_A コンストラクタ関数
// ------------------------------------------------------------
function MyFunc_A (){
}
// ------------------------------------------------------------
// MyFunc_B コンストラクタ関数
// ------------------------------------------------------------
function MyFunc_B (){
// 派生元コンストラクタを実行して初期化する
MyFunc_A.apply(this,arguments);
}
// ------------------------------------------------------------
// MyFunc_C コンストラクタ関数
// ------------------------------------------------------------
function MyFunc_C (){
// 派生元コンストラクタを実行して初期化する
MyFunc_B.apply(this,arguments);
}
// ------------------------------------------------------------
// MyFunc_B 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
// ------------------------------------------------------------
MyFunc_B.prototype = ObjectCreateByPrototype(MyFunc_A.prototype);
// ------------------------------------------------------------
// MyFunc_C 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
// ------------------------------------------------------------
MyFunc_C.prototype = ObjectCreateByPrototype(MyFunc_B.prototype);
// ------------------------------------------------------------
// MyFunc_A オブジェクトを作成する(Object → MyFunc_A)
// ------------------------------------------------------------
var obj_a = new MyFunc_A();
// ------------------------------------------------------------
// MyFunc_B オブジェクトを作成する(Object → MyFunc_A → MyFunc_B)
// ------------------------------------------------------------
var obj_b = new MyFunc_B();
// ------------------------------------------------------------
// MyFunc_C オブジェクトを作成する(Object → MyFunc_A → MyFunc_B → MyFunc_C)
// ------------------------------------------------------------
var obj_c = new MyFunc_C();
// ------------------------------------------------------------
// 出力テスト
// ------------------------------------------------------------
trace(obj_a instanceof Object); // true
trace(obj_a instanceof MyFunc_A); // true
trace(obj_a instanceof MyFunc_B); // false
trace(obj_a instanceof MyFunc_C); // false
trace(obj_b instanceof Object); // true
trace(obj_b instanceof MyFunc_A); // true
trace(obj_b instanceof MyFunc_B); // true
trace(obj_b instanceof MyFunc_C); // false
trace(obj_c instanceof Object); // true
trace(obj_c instanceof MyFunc_A); // true
trace(obj_c instanceof MyFunc_B); // true
trace(obj_c instanceof MyFunc_C); // true
■プロトタイプの継承と、カプセル化の例
プロトタイプを共有せずに、プロトタイプの継承を実現する
// ------------------------------------------------------------
// プロトタイプを指定して新しいオブジェクトを生成する関数
// ------------------------------------------------------------
function ObjectCreateByPrototype(prototype){
var f = function (){};
f.prototype = prototype;
return new f();
}
// ------------------------------------------------------------
// MyFunc_A という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc_A (){
// ------------------------------------------------------------
// プライベートな変数
// ------------------------------------------------------------
var _local_a = "a";
// ------------------------------------------------------------
// Aからデータを取得するメソッド
// ------------------------------------------------------------
this.getA = function (){
return _local_a;
};
// ------------------------------------------------------------
// Aにデータをセットするメソッド
// ------------------------------------------------------------
this.setA = function (v){
_local_a = v;
};
}
// ------------------------------------------------------------
// MyFunc_B という名前の関数を宣言する
// ------------------------------------------------------------
function MyFunc_B (){
// ------------------------------------------------------------
// 派生元コンストラクタ関数を実行する
// ------------------------------------------------------------
MyFunc_A.apply(this,arguments);
// ------------------------------------------------------------
// プライベートな変数
// ------------------------------------------------------------
var _local_b = "b";
// ------------------------------------------------------------
// Bからデータを取得するメソッド
// ------------------------------------------------------------
this.getB = function (){
return _local_b;
};
// ------------------------------------------------------------
// Bにデータをセットするメソッド
// ------------------------------------------------------------
this.setB = function (v){
_local_b = v;
};
}
// ------------------------------------------------------------
// MyFunc_B 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
// ------------------------------------------------------------
MyFunc_B.prototype = ObjectCreateByPrototype(MyFunc_A.prototype);
// ------------------------------------------------------------
// MyFunc_B オブジェクトを作成する(Object → MyFunc_A → MyFunc_B)
// ------------------------------------------------------------
var obj0 = new MyFunc_B();
var obj1 = new MyFunc_B();
// ------------------------------------------------------------
// 出力テスト
// ------------------------------------------------------------
trace(obj0.getA()); // "a"
trace(obj1.getA()); // "a"
trace(obj0.getB()); // "b"
trace(obj1.getB()); // "b"
// ------------------------------------------------------------
// 書き込みアクセステスト
// ------------------------------------------------------------
obj0.setA("書き込みA");
obj1.setB("書き込みB");
// ------------------------------------------------------------
// 出力テスト
// ------------------------------------------------------------
trace(obj0.getA()); // "書き込みA"
trace(obj1.getA()); // "a"
trace(obj0.getB()); // "b"
trace(obj1.getB()); // "書き込みB"