サイトトップ

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

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

黙示的なsetメソッドの代入式で戻り値がgetメソッドの値になる

ID: FN0402006 Product: Flash

Platform: All
Version: MX 2004

1. 現象
ActionScript 2.0クラスで黙示的なset/getメソッドを定義して、代入式によりプロパティを設定したとき、代入式の返す値がgetメソッドの戻り値になります。setメソッドで設定したプロパティの値と異なる値を、getメソッドから独自に返す処理を行っている場合に、この動作が問題になります。

// ActionScript 2.0クラス定義ファイル: MyRotation.as
class MyRotation {
  var _rotation:Number = 0;
  function get rotation():Number {
    return (_rotation+360)%360;
  }
  function set rotation(n:Number):Void {
    _rotation = n;
  }
}

// FLA(SWF)ファイル
// フレームアクション: テスト用
var obj:MyRotation = new MyRotation();
var n:Number = obj.rotation=-90;
trace(obj.rotation);  // 出力: 270
trace(n); // 出力: 270

本来の代入式は、代入された右辺の値を返します。したがって、複数のプロパティ/変数に連結した代入を行うと、すべてのプロパティ/変数には、最右辺の値が代入されます。

// フレームアクション
// MovieClipインスタンスmy_mcを配置
var n:Number = my_mc._rotation=270;
trace(my_mc._rotation);  // 出力: -90
trace(n); // 出力: 270

2. 原因
ActionScript 2.0の黙示的なsetメソッドは、代入式の記述により呼出されます。したがって、実際には代入式でなく、メソッドの呼出しが行われている訳です。そして、ActionScript 2.0の黙示的なset/getメソッドを定義すると、setメソッドはgetメソッドの戻り値を返す実装になっているようです。そのため、代入式の形式で呼出したsetメソッドの値として、getメソッドが呼出され、その戻り値が返されます。

ActionScript 2.0の黙示的なset/getメソッド の定義は、ActionScript 1.0のObject.addProperty()メソッドの処理に相当します。しかし、Object.addProperty()メソッドで定義したプロパティに(set関数をとおして)値を設定しても、get関数は呼出されません。

// フレームアクション
function MyRotation() {
}
MyRotation.prototype.getRotation = function() {
  return (_rotation+360)%360;
};
MyRotation.prototype.setRotation = function(n) {
  _rotation = n;
};
MyRotation.prototype.addProperty
  ("rotation", MyRotation.prototype.getRotation, MyRotation.prototype.setRotation);

// テスト用
var obj = new MyRotation();
n = obj.rotation=-90;
trace(obj.rotation);  // 出力: 270
trace(n);  // 出力: -90

3. 対処法
get関数へのアクセスは、おそらく意図的に追加されたものでしょう。その意味では、実装と考えるべきかもしれません。しかし、代入式の記述からは、代入された右辺値が返されると予測することが通常です。また、ECMA-262第4版提案(いわゆるECMAScript 4 Netscaoe Porposal)の関数(Functions)の節でも、黙示的なget/setメソッド(Getters and Setters)のsetterは値を返すべきでなく、「代入式の結果はsetterに渡された引数になる」[*1]とされています。

[*1] 原文は、"The setter should not return a value and should be declared as returning type Void or Never. The result of an assignment expression is the argument passed to the setter."と述べています。そして、以下のサンプルスクリプトでは、代入式(serialNumber = 42)が値42を返し、代入後のserialNumberの値として43が返されるとしています。

var x:Integer = 0;
function get serialNumber():Integer {return ++x}
function set serialNumber(n:Integer):Void {x=n}

もっとも、クラスから生成するオブジェクトインスタンスに型指定をしないと、Object.addProperty()メソッドと同じく、代入式の右辺値が返されます(内部的に、getメソッドの呼出し自体は行われているようです)。

// FLA(SWF)ファイル
// フレームアクション: テスト用
var obj = new MyRotation();  // 変数objが型指定されていないことに注意
var n:Number = obj.rotation=-90;
trace(obj.rotation);  // 出力: 270
trace(n);  // 出力: -90

ActionScript 2.0の黙示的なsetメソッドは、代入式のかたちで渡した代入(右辺)値を返さないという点で、通常の代入式やECMAScriptの仕様と齟齬(そご)をきたします。また、この動作はActionScript 1.0のObject.addProperty()メソッドと異なり、型指定の有無によって結果が変わる点で、整合性に問題があるといわざるをえません。したがって、混乱を避けるためには、黙示的ではなく明示的なset/getメソッドを使う方がよいのかもしれません(この場合、setメソッドの戻り値は任意に設定できます)。

_____

作成者: 野中文雄
作成日: 2004年2月28日


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