スクリプトがうまく動かないときに読むコラム① 「入れ子」
スクリプトを書いていて、「あれ? 思った動作と違うぞ?」ということはつきものです。
そんなときに「あっ、これが原因か!」とひらめくキッカケになるようなコラムが書けないかなと思いました。
画像入れ替えスクリプトの連載をしているところですが、コーヒーブレイク的にその事例と対処法を書き綴りたいと思います。
まずは例題のスクリプト。
「レイヤー名に数字が含まれていたらレイヤーロック、含まれていなければ何もしない」というスクリプトです(図1参照)。
[図1]
使いみちがあるようなないようなスクリプトですね(笑)
仮に「数字レイヤーロック」と名付けましょう。
下図2のスクリプトを実行すると、「実行していいか否か」を問うダイアログが表れます。
「はい」を押すと処理が始まり、終わると「処理が完了しました」というアラート(完了アラート)が出ます。
「いいえ」を押すと「処理を中断します」と出ます(中断アラート)
……ここまではいいのですが、実際に「いいえ」を押すと、中断アラートのあとに完了アラートが出てしまいます。少しヘンですね。
動作自体には別に問題はないのですが、中断したときは「中断します」でスッキリ終わりたいところです。
何がいけないのか?…それはずばり「alert("処理が完了しました")」の行の位置です。
[図2]
var layObj = app.activeDocument.layers; numLayerLock ();//関数の呼び出し function numLayerLock() {//処理を記した関数 var flag = Window.confirm ("処理を開始します","false ","テスト"); //はい、いいえダイアログの表示 if (flag) { //はいが押されたら処理開始 //↓こっから処理-------------------------------------- for (var i=0; i<layObj.length; i++){ if (layObj[i].name.match(/\d/)){ layObj[i].locked = true; } } //↑ここまで処理-------------------------------------- } else { alert ("処理を中断します");return //いいえで終了 } } alert ("処理が完了しました");//←完了アラートを出す行
関数内のすべての処理を終えたあとに、関数の外で完了アラートを出していますね。
中断処理は関数内で出しているので、中断し、returnで呼び出し元に処理が返ったあとに呼び出し元の処理「完了アラートを出す」が実行されてしまうのです。
中断も完了も関数内で処理する必要がありそうですね。かといって↓こんなのはもっとダメです(図3)。
[図3]
var layObj = app.activeDocument.layers; numLayerLock ();//関数の呼び出し function numLayerLock() {//処理を記した関数 var flag = Window.confirm ("処理を開始します","false ","テスト"); //はい、いいえダイアログの表示 if (flag) { //はいが押されたら処理開始 //↓こっから処理-------------------------------------- for (var i=0; i<layObj.length; i++){ if (layObj[i].name.match(/\d/)){ layObj[i].locked = true; alert ("処理が完了しました");//←★完了はここ } } //↑ここまで処理-------------------------------------- } else { alert ("処理を中断します");return //いいえで終了 } }
こいつを実行すると、レイヤーを消すたびに完了アラートが出るという、アレレな処理になってしまいます。
初心者のうちは一度はやってしまいそうですね。
そう、今回のコラムのテーマは「{}ブロックがネスト(入れ子)だらけになると、なんだかよく分からなくなるよね」というものです。
なので、スクリプトの処理そのものの解説は今回は割愛します。
正解は以下のとおりです。
[図4]
var layObj = app.activeDocument.layers; numLayerLock ();//関数の呼び出し function numLayerLock() {//処理を記した関数 var flag = Window.confirm ("処理を開始します","false ","テスト"); //はい、いいえダイアログの表示 if (flag) { //はいが押されたら処理開始 //↓こっから処理--------------------------------------- for (var i=0; i<layObj.length; i++){ if (layObj[i].name.match(/\d/)){ layObj[i].locked = true; } } //↑ここまで処理-------------------------------------- alert ("処理が完了しました");//←★完了はここ } else { alert ("処理を中断します");return //いいえで終了 } }
ループブロックの外側でかつ関数ブロックの内側に完了アラートを置くと、理想的な処理になると思います。
スクリプトが長くなるとどれがどのカッコなのかよく分からなくなるので、{}を打つたびに両カッコにコメントを付けると分かりやすいかもしれません(図5)。
また、基本的なことですが{}は必ず両方タイプしてから中身を書いていきましょう。
中身を書いてから閉じカッコ(})をタイプしようと思うと、ますます混乱しがちです。
[図5]
var layObj = app.activeDocument.layers; numLayerLock ();//関数の呼び出し function numLayerLock() {//01関数始め var flag = Window.confirm ("処理を開始します","false ","テスト"); //はい、いいえダイアログの表示 if (flag) { //02はいの処理開始 //↓こっから処理--------------------------------------- for (var i=0; i<layObj.length; i++){//03for始め if (layObj[i].name.match(/\d/)){//04if始め layObj[i].locked = true; }//04if終わり }//03for終わり //↑ここまで処理--------------------------------------- alert ("処理が完了しました"); }//02はいの処理終わり else {//05いいえの処理始め alert ("処理を中断します");return //いいえで終了 }//05いいえの処理終わり }//01関数終わり