連載: 2007年11月アーカイブ
前回オブジェクトについて書きましたが、それに関連して、もう少し関数をほじくり返してみます。
本題に入る前に、少し予備知識として話しておくことがあります。
Object には予めいくつかのプロパティやメソッドが定義されています。
これは Object に限った話ではないのですが、今はまだ Object の話しかしていないので、他の話はひとまずおいておきます。
また、ActionScript のバージョン 2 と 3 で定義されている内容は異なりますが、今は AS2 を基に話をすすめていきます。
で、Object に予め定義されているメソッドの中に toString() というものがあります。
これは Flash8 のヘルプには「指定されたオブジェクトをストリングに変換し、返します。」とあります。
つまり、この関数 toString() が定義されている Object を、人が読める形の String(文字列)に変換します。
用途は使いようによって様々ですが、今回は、主な目的のひとつである trace() 関数を使ったときに、出力する文字列を指定するために使います。
toString()の使い方は前回オブジェクトに定義した関数を使うときと同じです。
まずは以下のソースを見てください。
var obj = {}; // 変数 obj に新しく定義したオブジェクトを代入
var str = obj.toString(); // 変数 obj のtoString() 関数を呼び出して、結果を変数 str に代入
trace(str); // output : [object Object]
toString()の結果として"[object Object]"が出力されていることがわかります。実際は trace() 関数を使用すると、内部でtoString()を呼び出すようになっているので わざわざ toString() を実行する必要はありません。
trace()の処理をわかりやすくすると以下のような感じです。
function trace( arg )
{
出力( arg.toString() );
}
このtoString()を上書きして、新たに定義しなおしてみます。
var obj = {}
obj.toString = function() // 変数 obj が持つオブジェクトのメソッド toString を上書き
{
return "Method : toString"; // 定義内容を変更
}
trace( obj ); // output : Method : toString
trace() の結果から toString が意図した通りに処理が書き換えられたのが分かります。さて、前置きがかなり長くなりましたが、ここから本題です。
なるだけ分かりやすいようにHTMLの構造を真似てオブジェクトを組み立ててみます。
このオブジェクトを定義するために、折角ですから関数を用いることにします。
// ソースコード : 1
// オブジェクトを作成するための関数
function createObject( objName, objValue )
{
var obj = { name : objName }; // name プロパティを持つオブジェクトを定義
// name プロパティの値は引数 objName の値を設定する
obj.toString = function() // オブジェクトのtoString関数の処理を再定義
{
return objValue; // 実行結果に引数 objValue の値を返すようにする
}
return obj;
}
続いてこの関数を用いてオブジェクトを定義します。
// ソースコード : 2
// 関数createObjectを用いてオブジェクトを定義していく
var html = createObject("html","HTML");
html.head = createObject("head","HEAD");
html.head.title = createObject("title","続・オブジェクトと関数");
html.body = createObject("body","BODY");
さて準備ができましたので、次に定義したオブジェクトが、実際どのようになっているかを探ってみましょう。
trace( html ); // output : HTML上記のようにオブジェクト"html"を出力すると、関数createObject の引数に設定した objValue の値、つまり"HTML"が出力されました。
オブジェクト"html"のnameプロパティを参照する場合は以下のように書きます。
trace( html.name ); // output : htmlお気づきかも知れませんが、このオブジェクトは階層構造になっています。
オブジェクト "head" はオブジェクト "html" のプロパティとして設定されており、さらにオブジェクト "title" はオブジェクト "head" のプロパティとして定義されています。
つまり、"html" の name と head は、同じオブジェクト "html" のプロパティであるということです。
ですので、オブジェクト "head" を参照する(この場合 trace で出力する)には
trace( html.head );と書けばいいだけです。
それでは、オブジェクト "title" のnameプロパティを参照するにはどのように書けばよいでしょうか。
答えは次回に持ち越しますので試してみてください。
今度はソースコード:1の関数をを少し変更してみます。
// ソースコード : 1
function createObject( objName, objValue )
{
var obj = { name : objName };
obj.toString = function()
{
return objValue;
}
obj.outputName = function() // 新たにメソッドを追加
{
trace( this.name ); // name プロパティの値を出力する
}
return obj;
}
新たにthisという言葉が入っています。thisは実行しているオブジェクト自信を指すためのキーワードです。
オブジェクト"body"のメソッド"outputName()"を使うときも、プロパティと同様です。
html.body.outputName(); // output : BODYファイルやフォルダの関係は階層構造になっていますよね。
そのときファイルを指すURIは"/"(スラッシュ)を用いて階層構造を表しますが、それと同様です。
ただ"/"が"."になっているだけです。
以下に応用例を書いておきますので、また実際に実行してみていろいろ模索してみてください。
function node( name , child )
{
var obj = { name:name , child:child , parent:undefined };
child.parent = obj;
obj.toString = function()
{
return this.name + "/" + this.child.toString();
}
return obj;
}
var source = node("1st", node("2nd", node("3rd", undefined )));
trace( source );
var anchor = source.child.child;
trace( anchor.name );
anchor.child = node( "4th", undefined );
trace( anchor.child.name );
trace( anchor.parent.name );
undefinedとは、「指定された名前は、まだ定義されていません」という意味です。いきなり難易度を上げてしまったかもしれませんが、これが理解できれば後がかなりスムーズに理解できるようになると思いますので がんばって試行錯誤してください。
PICUP : this について
thisを用いることで参照先を明確にすることができます。
なぜ参照先を明確にしなければならないか、なのですが、その説明の前に以下のソースをコピーして実際にFlash上で実行してみてください。
// ---- ここから
var name = "VARIABLE";
var obj = {
name:"PROPERTY" ,
age:25
};
obj.getName_1 = function(){ trace( name ); }
obj.getName_2 = function(){ trace( this.name ); }
obj.getAge_1 = function(){ trace( age ); }
obj.getAge_2 = function(){ trace( this.age ); }
obj.getName_1(); // output : VARIABLE
obj.getName_2(); // output : PROPERTY
obj.getAge_1(); // output : undefined
obj.getAge_2(); // output : 25
// ---- ここまで
関数getName_1は、最初に定義した変数 name を参照していることが分かります。
一方、thisを指定したgetName_2は、きちんと自身のプロパティ name を参照しています。
また、getAge_1に至っては、参照先、age が見つけられずundefinedを返しています。
こちらもthisを付けて参照先を指定したgetAge_2では、意図した通り"25"を返しています。
このようにthisを使うのと使わないのとでは、大きく結果が異なってきます。
これまでより少し難しいかもしれませんが、慣れれば何てことはありません。
今回お話しするオブジェクト(Object)は ActionScript の根幹を成す基礎中の基礎なので必ず身につけましょう。
まずはオブジェクトを定義します。
定義する場所には変数を使います。
var obj = new Object();これで変数"obj"に新しいオブジェクトを定義して代入しました。
以下の方法でもオブジェクトを作成できます。
var obj = {};
こちらの方が、記述の手間も少ないですし、new を使うより処理も軽いのでこちらを使う頻度の方が高いでしょう。さて、オブジェクトの使い方ですが、オブジェクトには大きく分けて 2 種類の値、プロパティとメソッドを持たせることができます。
変な例えですが、オブジェクトを何かに例えて説明するなら、ドラクエのキャラクターでしょうか。
プロパティは「名前」や「レベル」や「攻撃力」などのキャラクターのパラメーターで、メソッドはそのキャラクターが持つ動作的な要素、つまり「たたかう」や「魔法」、「にげる」にあたります。余計に分かりにくかったかな。
実際オブジェクトの方はもっと自由ですが。
要は複数の変数を持つことができるんです。
var obj = { x:10 , y:20 };
trace(obj); // output : [object Object]
trace(obj.x); // output : 10
trace(obj.y); // output : 20
これは変数"obj"に"x"と"y"の 2 つのプロパティを持つオブジェクトを定義しています。プロパティ"x"と"y"は、それぞれ"10"と"20"を代入しています。
var obj = {};
obj.x = 20;
trace(obj.x); // output : 20
このように定義した後からプロパティを追加することもできます。次にメソッドです。
var obj = {
method_1: function(){ trace("function method 1") } ,
method_2: function(){ trace("function method 2") }
}
obj.method_1(); // output : function method 1
obj.method_2(); // output : function method 2
前回の内容を理解していれば、もうおわかりかと思いますが、メソッドとはオブジェクトが持つ関数です。しかし、前回とは少し関数の定義の仕方が違いますよね。
実は関数には 2 通りの定義方法があります。
前回紹介したのは指定した関数名で関数を定義して、その関数名を使って実行するものでした。
function funcName()
{
trace("Function");
}
funcName(); // output : Function
こんな感じに。もうひとつは変数に関数を代入する方法です。
var func = function()
{
trace("Function");
}
func(); // output : Function
つまり変数には関数も代入することができるのです。この場合、関数そのものに名前を定義しないため、無名関数とも呼ばれます。
下記はもう少し変数への代入を分かりやすくしたものです。
function func_1()
{
trace("Function");
}
var func_2 = func_1;
func_1(); // output : Function
func_2(); // output : Function
メソッドもプロパティと同様に、定義されたオブジェクトに追加することができます。
var obj = {};
obj.func = function()
{
trace("Function");
}
obj.func(); // output : Function
つまり、メソッドもオブジェクトの持つプロパティの一種であることがわかります。さらにオブジェクトのプロパティにオブジェクトを定義して、入れ子のようにすることも可能です。
var obj = {};
obj.prop = { name:"property" };
trace( obj ); // output : [object Object]
trace( obj.prop ); // output : [object Object]
trace( obj.prop.name ); // output : property
ActionScript は様々な機能があらかじめ定義されており、それは簡単に使うことができますが、
それらもすべて、このオブジェクトが元になっています。冒頭にも書きましたが、オブジェクトはスクリプトを組む上でかなり重要な位置にありますので その仕組みをきちんと理解しておいてください。
PICUP : 代入について
詳しくは後日書きますが、変数に数値や文字列を代入することと、定義したオブジェクトを代入することは少し意味が違います。
実際はオブジェクトの参照先を代入していると言った方がいいかもしれません。
以下にそれを表したサンプルを書きます、これもいろいろと試してルールを把握してください。
var obj_1 = { x:10 };
var obj_2 = { x:10 };
var refer = obj_1; // 参照
var val = obj_1.x; // 代入
trace( refer==obj_1 ); // output : true
trace( obj_1==obj_2 ); // output : true
trace( obj_1.x ); // output : 10
trace( refer.x ); // output : 10
val = 20;
trace( obj_1.x ); // output : 10
trace( refer.x ); // output : 10
refer.x = 20;
trace( obj_1.x ); // output : 20
trace( refer.x ); // output : 20
ActionScript にあらかじめ用意された関数を使うこともできますし、自分で関数を新たに作ることもできます。
関数の仕組みを知るために、まずは自分で作ってみましょう。
function funcName( x )
{
trace( "func : " + x );
}
関数を簡単に作ってみました。
上記の関数の記述について簡単に説明します。| function |
関数を定義するために必ず function をまず書きます。 変数を定義するときの var のようなものです。 |
| funcName | funcName はこの関数を呼び出すための名前です。 |
| () | 関数に関数外から値を渡したい場合に、この括弧()の中に値を参照するための名前(変数のようなもの)を定義します。 |
| x |
関数の外部から渡された値を参照するための名前です。 関数の外部から渡された値のことを引数(Arguments)といいます。 |
| {} | 括弧{}の中に、この関数が実行する処理を書きます。 |
ただ、これをプレビューしてみても何も起こりません。
関数は定義するだけでは何もおこらず、定義した関数内の処理も実行されません。
これを実行するためには、定義した関数を呼び出さなければなりません。
function funcName( x )
{
trace( "function : " + x );
}
funcName();
funcName(); という行を1行追記しました。これをプレビューしてみると、出力に「function : undefined」と表示されます。
undefined とは「値が見つかりませんでした。」という意味です。
例えば
var a; trace(a);とすると、同じように undefined と表示されます。
変数a に何も値を入れていないためです。
つまり引数 x に何も値が設定されなかったために x が undefined になったのです。
そこで funcName(); を以下のように書き換えてみます。
funcName( "関数" );これをプレビューすると「function : 関数」と表示されます。
関数の呼び出しは、同じスクリプト内であれば、関数の定義より上で呼び出しても、下で呼び出しても 同様に使用することができます。
funcName("呼び出し 1");
function funcName( x ){ trace( x ); }
funcName("呼び出し 2");
まだ、これでは有り難味が感じられないので、以下のように書き換えてみましょう。
function funcName( x , y )
{
trace( x+y );
}
funcName( 10 , 20 );
funcName( 10 , -5 );
funcName( 1 , 10 );
プレビューしてみると「30 5 11」が表示されました。つまり関数は一度定義すると、その中の処理がどれだけ長くなっても、簡単に何度も呼び出して実行することができるのです。
しかし、このままでは関数の内部ですべて完結してしまって、関数内で計算した結果を、次の計算に活かすといったことができません。
そのために return を追記します。
function funcName( x , y )
{
return x+y;
}
var a = funcName(10,20);//結果 : 30
var b = funcName(5,5);//結果 : 10
trace(a+b);//出力 : 40
以下にひとつ例を挙げておきますので、いろいろ書き換えてみて、関数の仕組みに慣れてください。
var a = 2;
var b = 3;
var res = func(func(10,5) / func(b,a));
trace("a="+a);
trace("b="+b);
trace("res"+res);
function func( a , b )
{
trace("func:a="+a);
trace("func:b="+b);
return a*b;
}
つづく
