条件(三項)演算子?:は、条件によって返す値を定めます。処理の速さよりも、条件によって異なる値を返すという、仕組みが明らかになるように用いるとよいでしょう。
○02-02-01 条件(三項)演算子?:は条件に応じた値を返す
条件演算子?:は、演算子ですので値を返します。演算対象となる項つまりオペランド(前掲Word 02-01-001参照)を3つもつため、「三項演算子」とも呼ばれます。まずは、シンタックスから確かめておきます。
条件 ? 式1 : 式2
?:演算子は、条件の評価がtrueのときは式1、falseなら式2の値を返します。戻り値はプロパティや変数に設定できます。たとえば、つぎのスクリプトは、今日がウィークディの場合はtrue、週末であればfalseを変数(bWeekday)に代入します。
var my_date:Date = new Date();
var bWeekday:Boolean = (my_date.day + 1) % 7 > 1 ? true : false;
|
同じ処理はifステートメントを使っても書けます。条件演算子?:と比べて行数は増えるものの、速さがとくに損なわれることはありません。
var my_date:Date = new Date();
if ((my_date.day + 1) % 7 > 1) {
bWeekday = true
} else {
bWeekday = false;
}
|
それでも、?:演算子を使った方が短くて見やすく、条件に応じた戻り値を代入するということがはっきりします。
○02-02-02 条件演算子?!はどのようなときに使うとよいか
条件演算子?:は、条件に応じた値を返します。このように機能が限定されている分、一般的なifステートメントなどより、内部的な最適化はしやすくなります。もっとも、本稿執筆時点の最新版Flash Player 10.1では、環境によって結果にばらつきがあり、つねに速いとはいえないようです。
しかし、前述のとおり、条件演算子の使用により、条件に応じた戻り値を得る処理であることが明らかにできます。また、そのような場合に用いれば、将来Flash Playerの最適化がさらに進められたときに、その恩恵が受けられることも期待できます。
条件に応じた戻り値を得る例としては、ある単位によって金額の変わる料金表が挙げられます。たとえば、定形外郵便物は重さに応じて料金が、下表02-02-001のように定められています。
表02-02-001■定形外郵便物の重さと料金
重さ |
料金 |
50gまで
|
120円
|
100gまで
|
140円
|
150gまで
|
200円
|
250gまで
|
240円
|
500gまで
|
390円
|
1kgまで
|
580円
|
2kgまで
|
850円
|
4kgまで
|
1,150円
|
定形外郵便物の重さを引数に渡して料金が返される関数(xGetPostage())は、以下のスクリプト02-02-001のように定義できます。かたちとしては、?:演算子が入れ子になっています。けれど、とくに改行やインデントでフォーマットを整えれば、条件の重さ(nWeight)が戻り値の料金(nPostage)にどう対応するのか捉えやすくなります(図02-02-001)。条件は括弧()で括ってわかりやすくしました。
スクリプト02-02-001【○】定形外郵便物の重さから料金を返す関数定義
- function xGetPostage(nWeight:Number):Number {
- var nPostage:Number = (nWeight <= 50) ? 120
: (nWeight <= 100) ? 140
: (nWeight <= 150) ? 200
: (nWeight <= 250) ? 240
: (nWeight <= 500) ? 390
: (nWeight <= 1000) ? 580
: (nWeight <= 2000) ? 850
: (nWeight <= 4000) ? 1150
: NaN;
- return nPostage;
- }
|
[編集用注] インデントをできれば下図02-02-001のようにお願いします。
図02-02-001■関数に定形外郵便物の重さを渡すと料金が返される


改行やインデントでフォーマットを整え、条件を括弧()で括ると、条件と戻り値の対応がより捉えやすくなる。
|
もちろん、つぎのように関数(xGetPostage)内の場合分けをifステートメントで書いても、処理のうえでことさら不利にはなりません。けれど、単にスクリプトの文字数だけでなく、条件に対する戻り値の捉えやすさでも、上記スクリプト02-02-001の方が優れているのではないでしょうか。
function xGetPostage(nWeight:Number):Number {
var nPostage:Number;
if (nWeight <= 50) {
nPostage = 120;
} else if (nWeight <= 100) {
nPostage = 140;
} else if (nWeight <= 150) {
nPostage = 200;
} else if (nWeight <= 250) {
nPostage = 240;
} else if (nWeight <= 500) {
nPostage = 390;
} else if (nWeight <= 1000) {
nPostage = 580;
} else if (nWeight <= 2000) {
nPostage = 850;
} else if (nWeight <= 4000) {
nPostage = 1150;
} else {
nPostage = NaN;
}
return nPostage;
}
|
前節02-01「条件の順序を考える」では、うるう年を調べるというお題で条件判定の最適化について考えました。そして、最適化した関数が再掲スクリプト02-01-004です。
スクリプト02-01-004【○】整理した条件の順序を最適化(再掲)
- function xIsLeapYear(nYear:int):Boolean {
- if (nYear % 4 != 0) { // 4で割切れない
- return false;
- } else if (nYear % 100 != 0) { // 100で割切れない
- return true;
- } else if (nYear % 400 != 0) { // 400で割切れない
- return false;
- } else {
- return true;
- }
- }
|
この関数(xIsLeapYear())の中に書いたifステートメントは、条件に応じたブーリアン(論理)値を返しています。したがって、条件演算子を使ってもよいでしょう。前掲スクリプト02-01-004を?:演算子による切り分けに書替えたのが、つぎのスクリプト02-02-002です。
スクリプト02-02-002【○】うるう年を条件演算子?:で判定して返す
- function xIsLeapYear(nYear:int):Boolean {
- return (nYear % 4 != 0) ? false
: (nYear % 100 != 0) ? true
: (nYear % 400 != 0) ? false
: true;
- }
|
[編集用注] インデントをできれば下図のようにお願いします。
|
○02-02-03 条件演算子?:の戻り値は加算後代入演算子+=に渡さない
条件演算子?:の返す値を代入するとき、気をつけたいことがあります。戻り値を代入演算子=でなく、加算後代入演算子+=に渡すと、処理が遅くなってしまうのです。
たとえば、前述01-04「何度もアクセスするプロパティやオブジェクトは変数に入れる」では、タイムラインに置いた3つのMovieClipインスタンスを水平にスクロールさせました(再掲図01-04-002)。
図01-04-002■タイムラインに置いた3つのMovieClipインスタンスを水平にスクロールさせる(再掲)
3つのインスタンスは水平にスクロールし、ステージの端を超えると反対側の端から表れる。
|
インスタンスを水平にスクロールしつつ、ステージの端を超えると反対側の端から表れるように、ifステートメントでインスタンスの水平座標に応じて移動しました(再掲スクリプト01-04-004)。
スクリプト01-04-004【○】プロパティ値や配列エレメントのインスタンスを予め変数にとる(再掲)
// フレームアクション
// 3つのMovieClipインスタンス(my0_mc〜my2_mc)を配置
- var nWidth:int = stage.stageWidth;
- var mcs_array:Array = [my0_mc, my1_mc, my2_mc]; // インスタンスの参照を配列に納める
- var nLength:uint = mcs_array.length; // プロパティ値を変数にとっておく
- addEventListener(Event.ENTER_FRAME, xScroll);
- function xScroll(eventObject:Event):void {
- for (var i:uint = 0; i < nLength; i++) {
- var my_mc:MovieClip = mcs_array[i]; // インスタンスを型指定した変数に入れる
// 変数のインスタンスを操作する
- my_mc.x += 5;
- if (nWidth < my_mc.x) {
- my_mc.x -= nWidth;
- }
- }
- }
|
スクリプト01-04-004のifステートメントは、条件によって異なる数値をインスタンスの水平座標(DisplayObject.xプロパティ)に加算(減算)しています。ですから、条件演算子を使って、つぎのスクリプト02-02-003のように書替えられます。
スクリプト02-02-003【△】条件演算子?:の戻り値を加算後代入演算子+=でプロパティに加える
- var nWidth:int = stage.stageWidth - 5;
- var mcs_array:Array = [my0_mc, my1_mc, my2_mc];
- var nLength:uint = mcs_array.length;
- addEventListener(Event.ENTER_FRAME, xScroll);
- function xScroll(eventObject:Event):void {
- for (var i:uint = 0; i < nLength; i++) {
- var my_mc:MovieClip = mcs_array[i];
// ?:演算子の戻り値を+=演算子で加える
- my_mc.x += (nWidth < my_mc.x) ? -nWidth : 5;
- }
- }
|
しかし、最適化が求められるときには、前掲スクリプト01-04-004のようにifステートメントを用いる方が処理は速くなります。
作成者: 野中文雄
作成日: 2011年3月7日