BeInteractive!

ActionScript理解度テストの解答です。

1. プリインクリメント・ポストインクリメント

var a:Number = 0;
trace(a++);
var b:Number = 0;
trace(++b);

出力

0
1

これはプログラミングの初歩ですね。a++の場合は加算前の値が、++aの場合は加算後の値が返ります。

2. 配列参照

var list:Array = [1,2,3,4,5];
var copy:Array = list;
copy[0] = 6;
trace(list);
trace(copy);

出力

6,2,3,4,5
6,2,3,4,5

初心者の人が良く間違う、配列のコピー「したつもり」コードです。

配列を代入する場合、参照が代入されるので、それを弄ると元の配列が変更されます。

3. メソッド参照

var o:Object = new Object();
o.a = 1;
o.f = function () : Void
{
    trace(this.a);
}

var f:Function = o.f;
f();

出力

undefined

一見、単に o.f を呼び出しているだけに見えますが、そうではありません。この場合、this に o は渡されないので、o上のプロパティを参照することはできません。

f.apply(o);

などを使いましょう。

4. 論理演算

var a:String = 'hoge';
var b:String = 'fuga';
trace(a || b);
trace(a && b);

出力

hoge
fuga

参考:http://f-site.org/articles/2004/03/26174042.html

5. ショートカットオペレータ

function f () : Boolean { return true; }
function f2 () : Boolean { return true; }
var a:Boolean;
var b:Boolean;

if ((a = f()) || (b = f2())) {
    trace(a);
    trace(b);
}

出力

true
undefined

論理演算で、最初の式が成り立っていれば次が実行されないという、Perlで良く使われるヤツ。

6. 参照渡し

function f (a:Number, b:Object) : Void
{
    a = 1;
    b.n = 2;
}

var n:Number = 0;
var o:Object = new Object();
o.n = 0;

f(n, o);

trace(n);
trace(o.n);

出力

0
2

プリミティブ型(数値など)は値渡し、複合型(オブジェクトなど)は参照渡しされます。値渡しされた変数は弄っても元の変数は変化しませんが、参照渡しされた変数を弄ると元の変数にも反映されます。

7. ECMAScriptにおけるブロック

var a:Number = 1;
{
    var a:Number = 2;
    trace(a);
}
trace(a);

出力

2
2

他言語に慣れている人にとっては予期しない結果かもしれませんが、ECMAScriptのブロックには新しいスコープを生成する機能はありません。

8. プロトタイプチェーン

var o:Object = { a:0 };
var b:Object = {};
b.__proto__ = o;
b.a = 1;
trace(o.a);

出力

0

ActionScriptの微妙な所です。ActionScriptでは、参照時にはプロトタイプチェーンを見ますが、代入時にはプロトタイプチェーンは見ません。

上記のコードの場合、オブジェクトb上にプロパティaが新たに生成され、値が設定されます。

9. クロージャ

function f (g:Function) : Void
{
    var b:Number = 2;
    g();
}

var a:Number = 0;
var b:Number = 1;
f(function () : Void
{
    trace(a);
    trace(b);
});

出力

0
1

ECMAScriptのクロージャは、「定義された位置に基づいて」決定されます。なので無名関数はグローバル上の変数しか参照できず、関数 f 内の変数 b は参照できません。

10. 未定義の変数の使用

function f () : Void
{
    var a:Number = 1;
}
function g () : Void
{
    b = 2;
}

f();
trace(a);
g();
trace(b);

出力

undefined
2

ECMAScriptでは、変数を参照するとスコープチェーンを辿って変数を探し、見つからなければそのスコープチェーンの最後のオブジェクト上に変数を作成します。

そのため、変数 b は関数 g だけのローカル変数として作成されるのではなく、グローバル上に定義されます。なので、関数外からもアクセスが出来てしまいます。

11. 関数の定義場所

for (var i:Number = 0; i < 3; ++i) {
    function mul (n:Number) : Number
    {
        return n * 3;
    }
    trace(mul(i));
}

出力

undefined
undefined
undefined

ECMAScriptでは、ブロック内での関数の定義は許されていません。そのため、関数は無いものとして扱われます。

12. 無名関数の呼び出し

trace((function(){ return 'hello'; })());

出力

undefined

参考:http://f-site.org/articles/2004/08/23074843.html

無名関数をその場で呼び出すことは出来ません。

13. カンマ演算子

var a:Number;
trace((a = 4, 5, 6));
trace(a);

出力

6
4

参考:http://f-site.org/articles/2005/08/31084857.html

14. toString

trace((1).toString() == String(1));
trace((1.5).toString() == String(1.5));
trace((true).toString() == String(true));
trace((null).toString() == String(null));
trace((undefined).toString() == String(undefined));

出力

true
true
true
false
false

参考:http://f-site.org/articles/2004/09/21022316.html

null 及び undefined には toString メソッドは存在しません。

15. true/falseの大文字小文字区別

var a:Boolean = true;

if (a == True) {
    trace('true');
}
else {
    trace('false');
}

出力

false

参考:http://f-site.org/articles/2005/02/10150043.html

true/falseの大文字小文字は区別されます。

16. AS2におけるビット演算時の数値の扱い

trace((0xffff0000 | 0x0000ffff));

出力

-1

一見 4294967295 になりそうですが、ビット演算をすると何故かsigned(符号付)値として認識されてしまいます。単に 0xffffffff だと違います。

17. クラスメンバの列挙

class Hoge
{
    public var a:Number = 1;
    public var b:Number = 1;
    
    public function Hoge ()
    {
        b = 2;
    }
    
    public function calc () : Number
    {
        return a + b;
    }
}

var h:Hoge = new Hoge();
for (var prop:String in h) {
    trace(prop);
}

出力

b

クラスメンバ列挙は、次のような法則があります。

  • 宣言しただけのメンバは列挙されない
  • メソッドは列挙されない
  • コンストラクタで初期化したメンバは列挙される

これは、コンストラクタで初期化したときにはじめて、オブジェクト上にプロパティが定義されるためです。それ以外は、プロトタイプチェーン上にあるため列挙されません。

18. インライン初期化の罠

class List
{
    private var list:Array = new Array();
    
    public function getList () : Array { return list; }
    public function dump () : Void { trace(list); }
}

var l:List = new List();
var l2:List = new List();

l.getList().push('a');
l2.getList().push('b');

l.dump();
l2.dump();

出力

a,b
a,b

インライン初期化されたメンバはプロトタイプチェーン上に存在するので、そのクラスの全てのインスタンス上で共有されてしまいます。

この場合、コンストラクタで初期化を行わないといけません。

19. グローバル関数と同名のメソッド

class Movie
{
    public function start () : Void { play(); }
    public function play () : Void { trace('play!'); }
}

var m:Movie = new Movie();
m.start();

出力

※何も出力されません

参考:http://www.fumiononaka.com/TechNotes/Flash/FN0406002.html

グローバル関数と同盟のメソッドを呼ぶときは、this をつけるようにしましょう。

20. 代入バグ

var a:Number = 0;
function f () : Number { return a++; }

var list:Array = [1,2,3,4,5];
list[f()] += 1;
list[f()] += 1;

trace(list);

出力

3,2,5,4,5

一見 2,3,3,4,5 になるように思えますが、Flashのコード生成にバグがあり、次のようなコードが生成されます。

list[f()] = list[f()] + 1;

つまり、1回の代入演算で関数fが2回呼び出されます。それによって、上記の様な結果になります。

この記事へのトラックバック

トラックバックはありません。

TrackBack URL:

http://www.be-interactive.org/trackback.php?id=146

この記事へのコメント

sasa wrote:
多少の自信はあったのに、いざ答え合わせしてみたら8問だけしかか合わなかった。。
いい勉強になりました。
yossy wrote:
ありがとうございます。
このテストが少しでもお役に立てれば幸いですヽ(´ー`)ノ

コメント書き込み:

カテゴリ

タグ

アーカイブ