サイトトップ

Director Flash 書籍 業務内容 プロフィール

Macromedia Flash非公式テクニカルノート

ドット演算子と配列アクセス演算子

ID: FN0507001 Product: Flash

Platform: All
Version: MX 2004 and above

インスタンスのプロパティにアクセスしたり、メソッドを呼出すときには「ドット演算子」(.)を使います。他方、Arrayクラスの配列インスタンスからエレメントを取出す角かっこ「配列アクセス演算子」([])を使って、配列にかぎらず、さまざまなオブジェクトのプロパティにアクセスすることができます。本稿では、ドット演算子(.)と配列アクセス演算子([])について、その意味と使い方をご説明します。なお本稿は、ActionScript 2.0にもとづく解説です。ActionScript 3.0については、FN1107002「ドット演算子と配列アクセス演算子」をお読みください。

1. ドット演算子[*1]
ドット演算子(.)は、オブジェクトのプロパティやメソッドを参照するために用いられます。たとえば、メインタイムラインの現行(再生ヘッドのある)フレームは、メインタイムラインを参照する_root識別子をターゲットにして、MovieClip._currentframeプロパティで取得することができます。

スクリプト001■MovieClip._currentframeプロパティを参照

// メインタイムラインの現行フレームを変数nFrameに格納[*2]
var nFrame:Number = _root._currentframe;

また、メインタイムラインの第10フレームに移動して再生を続ける場合には、_rootに対してMovieClip.gotoAndPlay()メソッドを呼出します。

スクリプト002■MovieClip.gotoAndPlay()メソッドを呼出

// メインタイムラインの第10フレームに移動して再生
_root.gotoAndPlay(10);

スクリプト001で、メインタイムラインに変数nFrameを宣言して、フレーム番号を格納しました。この変数の値を[出力]パネルに表示するには、つぎのステートメントを記述します。

スクリプト003■メインタイムラインの変数値を参照

// メインタイムラインに設定した変数nFrameの値を出力
trace(_root.nFrame);

ActionScriptが準拠するECMAScriptては、メソッドはプロパティに含まれます[*3]。また、変数もユーザー定義プロパティと考えることができます。したがって、ドット演算子(.)は、オブジェクトのプロパティにアクセスする機能をもつものといえます。

ドット演算子(.)は、階層化されたMovieClipのターゲットパスを参照する場合にも用いられます。たとえば、メインのタイムラインに配置されたMovieClipインスタンスmy_mcの水平座標を10ピクセル右に移動するには、つぎのようにターゲットパス(絶対パス)を指定してスクリプトを書きます。

スクリプト004■メインタイムラインに配置したMovieClipの座標を移動

// メインタイムラインに配置したインスタンスmy_mcの水平座標に10加算
_root.my_mc._x += 10;

_rootのつぎのドット演算子(.)に続けてMovieClipが指定されているのは、インスタンスmy_mcが_rootのプロパティと捉えられていることを意味します。プロパティは、単純な数値や文字列などのプリミティブ値だけにかぎりません。クラスのインスタンスを設定することも可能で、MoiveClipインスタンスもその中に含まれるのです。

このように見てくると、ドット演算子(.)は、オブジェクトのプロパティにアクセスする手段だとまとめることができます。つまり、ドット演算子(.)は、左側オペランド(被演算子)[*1]のオブジェクトを参照して、右側オペランドのプロパティを取得します。

[*1]「演算子」(operator)とは、演算記号のことです。演算子を用いて演算の対象とする値や変数は、「被演算子」または「オペランド」(operand)と呼ばれます。一般に式は、演算子とオペランドで構成されます。

[*2] 値を格納する変数nFrameは、ActionScript 2.0を用いてNubmerで型指定しています。

[*3] 「ECMA-262第3版」の「4.2 言語の概要」には、「プロパティは、他のオブジェクトや プリミティブ値 、メソッド を保持するコンテナである」と定められています。

また、David Flanagan『JavaScript第3版』(O'REILLY)は、つぎのように述べます。「名前の付けられたデータ集合をオブジェクトと呼びます。個々のデータ値をそのオブジェクトのプロパティといいます」。そして、「特定のオブジェクトのプロパティに格納された関数をメソッドといいます」(p.45)。

2. 配列アクセス演算子
配列アクセス演算子([])も、オブジェクトのプロパティを取得します[*4]。ドット(.)の替わりにブラケット([])を用いるほか、大きく異なるのはプロパティを文字列で指定することです。たとえば、メインタイムラインに設定した変数nFrameの値を[出力]パネルに表示するには、配列アクセス演算子([])を使ってつぎのように記述します。

スクリプト005■メインタイムラインの変数値を配列アクセス演算子[]で参照

// メインタイムラインに設定した変数nFrameの値を出力
trace(_root["nFrame"]);

配列アクセス演算子([])に変数を指定すると、その変数から文字列を取出して、文字列の名前のプロパティにアクセスします。

スクリプト006■変数名の文字列を別の変数に格納して値を参照

// メインタイムラインに設定した変数nFrameの値を出力
// 変数名"nFrame"を別の変数の値として文字列で格納
var myPropertyName:String = "nFrame";
trace(_root[myPropertyName]);

プロパティを文字列で指定できるということは、上記のようにプロパティ名を変数に格納したり、あるいは文字列に別の変数を組込むことが可能になります。つまり、プロパティ名が、ダイナミックに変更できることを意味します。

タイムラインに連番のインスタンス名をつけたmy0_mc〜my4_mcというMovieClipが存在するとき、それらすべての水平座標を10ピクセル右に移動するには、つぎのようなループ処理を行います。

スクリプト007■文字列と変数を連結してインスタンス名を指定

// タイムラインにmy0_mc〜my4_mcが配置
// すべてのインスタンスの水平座標を移動
for (var i:Number = 0; i<5; i++) {
   this["my"+i+"_mc"]._x += 10;
}

ドット演算子(.)でプロパティにアクセスするとき左側オペランドにオブジェクトを指定しなければならないのと同じく、配列アクセス演算子([])もその左側にオブジェクト参照が必要です。配列アクセス演算子([])の左側にオブジェクトを指定しないと、まったく違った意味に解釈されます。たとえば、以下のステートメントは、スクリプトエラーになります。

["my_mc"]._x = 100;

オブジェクト参照なしに配列アクセス演算子([])を記述すると、Arrayクラスのインスタンスである配列を生成する処理になり[*5]、オブジェクトを参照したプロパティの取得になりません。配列の作成と同時にプロパティを設定することはできませんので、スクリプトエラーが発生します。

ドット演算子(.)でアクセスできるプロパティは、すべて配列アクセス演算子([])で操作することが可能です。したがって、ActionScriptの定義済みプロパティやメソッドも、配列アクセス演算子で処理することができます。通常はドット演算子(.)の方が記述しやすいので、定義済みプロパティに対して配列アクセス演算子があえて使われることは多くありません。しかし、プロパティをダイナミックに変更したい場合には、配列アクセス演算子([])の存在が大きな意味をもちます[*6]。

スクリプト008■MovieClipプロパティやメソッドを配列アクセス演算子で操作

// メインタイムラインの現行フレームを変数nFrameに格納
var nFrame:Number = _root["_currentframe"];

// メインタイムラインの第10フレームに移動して再生
_root["gotoAndPlay"](10);


[*4] 配列すなわちArrayクラスのエレメント(要素)にアクセスするとき用いられるため、この名で呼ばれます。しかし、ここで説明する内容は、配列とは直接関係ありません。もっとも、配列もオブジェクトですので、ここで述べたことを、配列に適用することは可能です。

[*5] 以下のふたつのステートメントは、同じ配列を作成します。

スクリプト009■配列を生成する2種類のステートメント

var a0_array:Array = ["my_mc"];

var a1_array:Array = new Array("my_mc");

// [デバッグ] > [変数のリストアップ]:
変数 _level0.a0_array = [オブジェクト #1, クラス 'Array'] [
     0:"my_mc"
   ]
変数 _level0.a1_array = [オブジェクト #2, クラス 'Array'] [
     0:"my_mc"
   ]

[*6] 操作すべきプロパティ名を変数に格納して、処理内容がダイナミックに変わるサンプルスクリプトを、参考として掲げます。以下のスクリプトをMovieClipシンボル内のフレームアクションとして設定すると、上下左右の矢印キーでインスタンスを1ピクセルずつ移動できます。

左右の矢印キーならMovieClip._xプロパティ、上下の矢印ではMovieClip._yプロパティを操作しますので、これらのプロパティ名を変数に入れて取出します。どのキーが押されたかは、ifステートメントで判別するのが普通でしょう。しかし、このスクリプトではキーコードがユニークな整数であることに着目して、操作内容(プロパティ名と移動ピクセル数)を配列に格納しました。

押されたキーコードをインデックスとして、配列から操作内容のオブジェクトを取出します。したがって、キーコードから直ちに操作内容が決まり、どのキーが押されたかの判定は不要になります。関係のないキーが押された場合には、配列エレメントが存在しないことにより判別ができます。

スクリプトの処理を詳しく解説することは本稿の目的ではありませんので、上述の考え方をヒントに内容をご検討ください。

スクリプト010■矢印キーでMovieClipを上下左右に移動

// MovieClip: 矢印キーで移動するインスタンス
// 第1フレームアクション
// [1]リスナーオブジェクトの生成
var oListener:Object = new Object();
// [2]キーコードをインデックスにして操作するプロパティと値を定義
var operation_array:Array = new Array();
operation_array[Key.LEFT] = {property_str:"_x", nValue:-1};
operation_array[Key.RIGHT] = {property_str:"_x", nValue:1};
operation_array[Key.UP] = {property_str:"_y", nValue:-1};
operation_array[Key.DOWN] = {property_str:"_y", nValue:1};
// [3]操作対象のタイムラインと[2]の配列をリスナーオブジェクトに設定
oListener.target_mc = this;
oListener.operation_array = operation_array;
// [4]キーイベントの処理
oListener.onKeyDown = function() {
  var oOperation:Object = this.operation_array[Key.getCode()];
  if (oOperation) {
    // trace(Key.getCode());  // テスト用
    var property_str:String = oOperation.property_str;
    var nValue:Number = oOperation.nValue;
    this.target_mc[property_str] += nValue;
  }
};
// [5]リスナーオブジェクトの登録
Key.addListener(oListener);

3. eval()関数との比較
ドットシンタックスを使って、しかも変数やプロパティを文字列で指定したい場合には、eval()関数を利用します。eval()関数は、文字列で記述したドットシンタックスのパスを、そのパスが参照する値に変換します。たとえば、メインタイムラインに設定した変数nFrameの値を[出力]パネルに表示するには、eval()関数を用いてつぎのように記述することができます。

スクリプト011■メインタイムラインの変数値をeval()関数で参照

// メインタイムラインに設定した変数nFrameの値を出力
trace(eval("_root.nFrame"));

ドットシンタックスや配列アクセス演算子([])との大きな違いは、ふたつあります。第1は、参照するターゲットを指定しないことです。つぎのような記述は、シンタックスエラーになります。

   _root.eval("nFrame"));

大きな違いの第2は、eval()関数の戻り値に直接代入することができません[*7]。以下のステートメントも、シンタックスエラーになります。

   eval("_root.nFrame") = 10;

変数やプロパティを文字列で指定して、値を代入したいときには、配列アクセス演算子([])もしくはset variableステートメントを使います。

スクリプト012■文字列で指定した変数に値を代入

// メインタイムラインに設定した変数nFrameに値を代入
_root["nFrame"] = 10;
// set variableステートメントで値を設定することも可能
// set("_root.nFrame", 10);

許されないのは、eval()関数の戻り値に対する直接の代入です。取得した戻り値を参照して変数やプロパティにアクセスすれば、それらへの値の代入は可能になります。たとえば、メインタイムラインにMovieClipインスタンスmy_mcが配置されている場合、eval()関数を使って、つぎのようにMovieClip._xプロパティを設定することができます。

スクリプト013■文字列で指定した変数に値を代入

// メインタイムラインに配置したMovieClipインスタンスのX座標を設定
eval("_root.my_mc")._x = 0;

配列アクセス演算子([])と比べて、eval()関数の有利な点は、複数階層のパスをひとつの文字列として指定できることです。たとえば、メインタイムラインにMovieClipインスタンスcar_mcがあり、その中のtire_mcのプロパティを設定する場合、文字列のインスタンス名を使って記述すると、それぞれつぎのようなステートメントになります。

スクリプト014■複数階層のパスを参照してプロパティを設定

// _root.car_mc.tire_mcのプロパティ値を設定
// 配列アクセス演算子を使った場合
_root["car_mc"]["tire_mc"]._rotation += 10;
// eval()関数を使った場合
eval("_root.car_mc.tire_mc")._rotation += 10;

深い階層のパスをひとつの文字列で指定できる点は、eval()関数を使う利点になります。もっとも、そのようなかけ離れた階層の変数やプロパティを操作するようなスクリプティングのデザインは、再考してみる必要があるでしょう。その意味では、eval()関数を使わなければならない場合というのは、あまり多くはないと思われます[*8]。

[*7] Flash Player 4では、eval()関数の戻り値に直接値を代入することが許されます。Flash Player 6以降から、仕様が変更されました(TechNote「左辺にあるEval()が正常動作しない」参照。なお、Flash 8ヘルプのeval()関数についての記述には、誤りがあります。)。

[*8] もうひとつeval()関数を使う利点として、参照を取りたくないつまり「デフォルト参照」を使いたい場合が考えられます。たとえば、メインタイムラインにTextFieldインスタンスmy_txtがあり、LoadVarsクラスを使ってロードした外部テキストファイルの値を、my_txtに設定したいというケースです。なお、外部テキストファイルは同階層の"data.txt"で、その中には変数myVarの値が指定されているものとします。

スクリプト015■eval()関数でデフォルト参照を利用

// タイムライン: _root
// TextFieldインスタンス_root.my_txtが配置
// フレームアクション
var fieldName_str:String = "my_txt";
var my_lv:LoadVars = new LoadVars();
my_lv.onLoad = function (bSuccess:Boolean):Void {
   eval(fieldName_str).text = this.myVar;
}
my_lv.load("data.txt");

ただ、この場合も、配列アクセス演算子([])を用いた記述は可能ですので、eval()関数を使わなければならないということはありません。

スクリプト016■ターゲットをオブジェクトに設定して配列アクセス演算子を利用

// タイムライン: _root
// TextFieldインスタンス_root.my_txtが配置
// フレームアクション
var fieldName_str:String = "my_txt";
var my_lv:LoadVars = new LoadVars();
my_lv.target_mc = this; // 参照すべきタイムラインを設定
my_lv.onLoad = function(bSuccess:Boolean):Void {
   // eval(fieldName_str).text = this.myVar;
   this.target_mc[fieldName_str].text = this.myVar;
}
my_lv.load("data.txt");

_____

作成者: 野中文雄
更新日: 2011年7月5日 FN1107002「ドット演算子と配列アクセス演算子」へのリンクを追加。
更新日: 2006年8月6日 注釈*7の記述を修正および参考URLを追加。
更新日: 2005年12月27日「3. eval()関数との比較」の項を追加
作成日: 2005年7月31日


Copyright © 2001-2006 Fumio Nonaka.  All rights reserved.