|
お世話になります。 よろしくお願いします。
以下のExtend Scriptソースがあるのですが、後半にあるアラートをコメントアウトするしないで、InDesignドキュメントの動作結果が変わります。
アラートを実行した時の動作が、本来求めている動作です。 動作が変わってしまう理由を説明できるようになりたいのですが、どなたかご教示いただけないでしょうか。
長方形オブジェクトを変数に代入した後、何かしらプロパティを参照するかしないかで動作が変わっているようだというところまでは気づきました。 以下のソースでは、この参照をアラートの部分で行っています。 (ですので、アラートの部分は、コンソールへ書き出すでも何でもいいので、アラートにしている部分はあまりつっこまないでいただけるとうれしいです。)
実は、職場の高卒のルーキーが一生懸命勉強してくれていて、以下のようなソースを書いてくれたのですが……理由が説明できず、今回こちらに質問をさせていただきました。
私以外プログラマーが職場にいないので、わからないで終わらすのは申し訳なく、かと言ってなんとググらせればいいかヒントもだせず、とりあえず調べると言って宿題をあずかりましたw
お手数をおかけします。 よろしくお願いします。
///// ここから下がソースです。 //////////
var doc = app.documents.add();
// ● 長方形を適当に作成 var rct;
for (var i = 0; i < 5; i++) { rct = doc.rectangles.add(); rct.geometricBounds = [ i * i * 10, i * i * 5, i * i * 10 + i * i + 10, i * i * 5 + i * i + 5 ]; rct.fillColor = doc.swatches[i + 4]; rct.name = (i + 1).toString(); }
// ● 作成した全長方形から、もっとも上下左右にある長方形を調査して取得 var mTop = doc.rectangles[0].geometricBounds[0]; var mTopRct = doc.rectangles[0];
var mLeft = doc.rectangles[0].geometricBounds[1]; var mLeftRct = mTopRct;
var mBottom = doc.rectangles[0].geometricBounds[2]; var mBottomRct = mTopRct;
var mRight = doc.rectangles[0].geometricBounds[3]; var mRightRct = mTopRct;
var rct = doc.rectangles; for (var i = 1; i < rct.length; i++) { if (rct[i].geometricBounds[0] < mTop) { mTop = rct[i].geometricBounds[0]; mTopRct = rct[i]; }
if (rct[i].geometricBounds[1] < mLeft) { mLeft = rct[i].geometricBounds[1]; mLeftRct = rct[i]; }
if (rct[i].geometricBounds[2] > mBottom) { mBottom = rct[i].geometricBounds[2]; mBottomRct = rct[i]; }
if (rct[i].geometricBounds[3] > mRight) { mRight = rct[i].geometricBounds[3]; mRightRct = rct[i]; } }
// ● 以下のアラートの実行有無で、InDesignドキュメントの動作が変わります alert( mTopRct.geometricBounds[0] + ", " + mLeftRct.geometricBounds[1] + ", " + mBottomRct.geometricBounds[2] + ", " + mRightRct.geometricBounds[3] );
// ● 作成 var rctLast = doc.rectangles.add(); rctLast.geometricBounds = [ mTopRct.geometricBounds[0], mLeftRct.geometricBounds[1], mBottomRct.geometricBounds[2], mRightRct.geometricBounds[3] ];
|
No.9926 2020/06/22(Mon) 22:39:56
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36
|
Re: スクリプトの動作結果が変わる理由が説明できるようになりたいです / お〜まち |
|
|
|
これは「値渡し」と「参照渡し」を理解していないと説明が難しいですね。 私も正確には理解していないので、うまく説明できないのですが(^^;
端的に言うと「// ● 作成」の次の行 var rctLast = doc.rectangles.add(); で長方形が新たに作られることによって、mTopRct、mLeftRct、mBottomRct、mRightRctの参照先が移動しちゃうんです。 ここを var rctLast = doc.ovals.add(); というふうに楕円にしてしまうと、Alert行の有無に関係なく、望んだ大きさの楕円がつくられますので試してみてください。
逆にAlert行があることによって参照先の移動が起こらないことが、私には説明できません。そこは誰か詳しい人、お願いします。
|
No.9927 2020/06/23(Tue) 00:53:11
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.98 Safari/537.36
|
|
Re: スクリプトの動作結果が変わる理由が説明できるようになりたいです / ヒース |
|
|
|
お〜まちさん
ご返信ありがとうございます。 スレ主です。
「値渡し」と「参照渡し」については、私は理解できているレベルだとご認識いただければと思います。 (昔、思うように動作してくれず、一人でデバッグしながらネットでググり、長時間かけてなんとか理解にこぎつけることが出来ました。)
ですので、今回の動作はバグではなく、『var rctLast = doc.rectangles.add();』で参照先が移動しているんだろうなぁ〜というのは、想像しました。 だとしても、『Alert行の有無で動作が変わることが謎』という状況です。 どなたかご返信いただけること、気長に待ちたいと思います。
>> >> var rctLast = doc.ovals.add(); >> というふうに楕円にしてしまうと、Alert行の有無に関係なく、望んだ大きさの楕円がつくられますので試してみてください。 >> こちらの情報、ありがとうございました。 早速試し、動作の確認が取れました。 前述した「『var rctLast = doc.rectangles.add();』で参照先が移動しているんだろうなぁ〜」という想像で終わらせていたので、これで検証ができたのかなと認識しています。
想像で終わらさず検証の実施を、もっとクセ付けないとですね。 ありがとうございました。
|
No.9928 2020/06/23(Tue) 08:50:02
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36
|
|
Re: スクリプトの動作結果が変わる理由が説明できるようになりたいです / Uske_S |
|
|
|
ヒースさん: これはExtendScriptの仕様というかクセというか見方によってはバグみたいなものです。 例えば、alertメソッドをコメントアウトして以下の4行を同じ場所に追加して見てください。
mTopRct = mTopRct.getElements()[0]; mLeftRct = mLeftRct.getElements()[0]; mBottomRct = mBottomRct.getElements()[0]; mRightRct = mRightRct.getElements()[0];
alertメソッドの有無に関わらず同じ結果になるはずです。
これの詳細は下記のブログに書かれています。 http://sysys.blog.shinobi.jp/Entry/113/
コレクションオブジェクトへの追加と削除はちょっと厄介でして、コレクションオブジェクトのid、for文でループさせる際のindexを見てもらうとなんとなく変なことはわかっていただけるかもしれません。
いずれにせよ、コレクションオブジェクトへの追加や削除はgetElementsメソッドを利用してもらったほうが確実です。
|
No.9929 2020/06/23(Tue) 15:24:16
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36
|
|
Re: スクリプトの動作結果が変わる理由が説明できるようになりたいです / Uske_S |
|
|
|
追記です。
alertメソッドなどにオブジェクトを引数として渡すと、内部的にはStringコンストラクタを経由し、オブジェクトの参照先が文字列に変換されます(暗黙的型変換)。 このタイミングでブログのisValidの副作用にあるような、オブジェクト参照先の再取得が起こっていると僕は考えています。
先ほどのgetElementsメソッドのところを下記のようにしても同じ結果が得られます。
String(mTopRct.geometricBounds[0]); String(mLeftRct.geometricBounds[0]); String(mBottomRct.geometricBounds[0]); String(mRightRct.geometricBounds[0]);
特に値を代入せずとも、値をStringコンストラクタに通すだけで結果が変わるわけです。
|
No.9930 2020/06/23(Tue) 15:30:56
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36
|
|
Re: スクリプトの動作結果が変わる理由が説明できるようになりたいです / Uske_S |
|
|
|
もういっこ追記です。
getElementsを利用するケースはもうひとつあって、オブジェクトのインスタンスを変更するケースです。 例えばコード中でTextFrameをRectangleに変えるようなケース。 InDesignのスクリプトであればTextFrames.add()したあとにContentTypeを変更するなどして実装できます。
具体的には下記のような場合に有効です。 var doc = app.activeDocument;
var f = doc.textFrames.add(); //この時点で f は TextFrame f.contentType = ContentType.GRAPHIC_TYPE; //グラフィックフレームに変更しても… $.writeln(f.toSpecifier()); //結果は TextFrame $.writeln(f.hasOwnProperty("contents")); //結果は true //f.contents = "hoge"; //<-これはエラーになる
f = f.getElements()[0]; //getElementsメソッドを挟むと… $.writeln(f.toSpecifier()); //結果は rectangle $.writeln(f.hasOwnProperty("contents")); //結果は false
|
No.9931 2020/06/23(Tue) 15:43:38
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36
|
|
Re: スクリプトの動作結果が変わる理由が説明できるようになりたいです / (z-) |
|
|
|
流れ上、ゴミみたいな返信になりますがw
for (var i = rct.length - 1; i >= 0; i--) {
でも回避できますね。
|
No.9932 2020/06/23(Tue) 16:42:14
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Safari/605.1.15
|
|
Re: スクリプトの動作結果が変わる理由が説明できるようになりたいです / ヒース |
|
|
|
Uske_Sさん (z-)
ご返信ありがとうございます。 スレ主です。
取り急ぎのお礼です。 ちょっと、じっくり読み、実際に動かしてみてから、改めて返信させていただきます。
|
No.9933 2020/06/23(Tue) 17:06:14
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36
|
|
Re: スクリプトの動作結果が変わる理由が説明できるようになりたいです / ヒース |
|
|
|
(z-)さん
スレ主です。 敬称モレ、大変失礼しました。
|
No.9934 2020/06/23(Tue) 17:07:42
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36
|
|
Re: スクリプトの動作結果が変わる理由が説明できるようになりたいです / あるふぁ |
|
|
|
Uske_Sさんが紹介してくれたブログを書いたものですが、 いやこれはそこに書いたことでは説明できない、というかそれを書いたときかなり調査不足だったなあと反省するところでして
私も今知ったばかりなので想像というか1つの解釈でしかないのですが、
rct[i]を変数に代入した段階では、doc.rectanglesのi番目という情報が入っただけ ↓ 何かしらのプロパティを取得したとき、はじめてInDesign上のオブジェクトと紐づけされる ↓ 紐づけされた後はrectangleを増減しても参照がずれることはない
ということかなと思います。
いやはや私も経験上はPageItem系オブジェクトはアイテムが増減してもずれないイメージだったのですが、これ(http://sysys.blog.shinobi.jp/Entry/113/)を書くとき実験したらずれたので、あれ?と思いながらもずれるものとして書いちゃったのですが、もう少し詳しく検証しておくべきでした。
ただ本当に「1つでもプロパティを取得すれば参照がずれることはない」と言えるのかは不明です。 既知の例外としては上記ブログ記事に書いたように、アイテム増減後にisValidプロパティにアクセスするとずれます。
ご承知の上だろうと思いますが今回の例で言えばmTopRctから取得しなおさずにmTop等を使っておけばよかったわけで、 ほかにもUske_SさんのおっしゃるようにgetElementsを使ったり、 (z-)さんのおっしゃるようにずれても問題ない順番で処理するとか、 そんなふうにできるだけ「ずれないはず」に頼らないコードを書くようにしたいものですね
|
No.9935 2020/06/23(Tue) 17:48:48
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0
|
|
Re: スクリプトの動作結果が変わる理由が説明できるようになりたいです / ヒース |
|
|
|
あるふぁさん
ご返信ありがとうございます。 スレ主です。
取り急ぎのお礼です。 他の方の返信確認後、改めて返信させていただきます。
|
No.9936 2020/06/24(Wed) 10:33:35
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36
|
|