【AEスクリプト】valueは参照渡しか、値渡しか?

エクスプレッションと違い、スクリプトでは、位置や回転の値を得るためには『○○.position』だけではダメで、
『○○.position.value』まで書かねばなりません。実際はエクスプレッションでも『○○.position.value』と書くのが正式なものなんですが、AEが記述を補完してくれているわけです。

で、表題の件なんですが、まずは参照渡しと値渡しを説明します。
例えば、『1』という数値を変数aに入れたとして、その変数aを今度は変数bに入れたとします。この場合、変数aと変数bはそれぞれ独自に『1』という数値を持つこととなり、aとbは同じ『1』を共有しているわけではありません。aに新たに別の数値を入れたところで、bに変化はなく『1』のまま、逆もしかりです。
次の例です。同じように、とある値をaに入れて、それをbに入れますが、今度は『1』という数値ではなく[1,2,3]という配列を入れてみます。そうすると、aとbは同じ[1,2,3]という配列を共有します。共有しているので、aかbのどちらかの配列内要素を変更すると、その変更はbにも及びます。例えば、aの配列にpushメソッドで要素を足すと、bはaと同じ配列を共有しているのでbも同じ形になります。

前者の“共有しない”変数間の渡しを『値渡し』、後者の“共有する”渡しを『参照渡し』と言います。
んで、どういうルールでこの違いが出てくるかは決まっています。
値渡し プリミティブ型(数値、文字列、真偽値、null、undefined)
参照渡し それ以外(配列とかオブジェクト)
です。
値渡しはコピー、参照渡しは共有って感じですね。

以上の参照渡しと値渡しの違いは、配列を使ってコードを書くようになるとだいたいぶち当たる問題です。「元の配列を複製して要素を入れ替えて、元の配列&入れ替えた配列の両方使おう」とかやってみると「あれ…なぜか元の配列まで順番変わってるんですけど」とかですね。やっていたのは複製ではなく共有だったというオチです。

上記を理解し「ああ、AEのスクリプトというかJavaScriptにはこんな仕様があるのかー」と、配列の扱いをマスターしたと思ったところで、ふと疑問が生じます。

position.valueの値は[960,540,0]とかの配列です。参照&値渡しのルールで考えれば、

var mPos = app.project.activeItem.selectedLayers[0].position.value;

と書いた場合、配列を変数に入れているんですから『参照渡し』になるはず、
つまり○○.position.valueというオブジェクトのプロパティとmPosという変数は同じ配列を共有した、
ということになるはずです。

が、そうはならないんですねえ。
結論から言いますと、valueはどんな型であれ、変数に代入するとコピーされます
配列に関して言えば、配列内の要素もコピーされたものとなります。
ここが、JavaScriptの基本ルールとAEのスクリプトのちょっとした違いなんですね…。

実際、mPosの値をspliceメソッドで[960,540,100]にしてみると、
mPosの値は[960,540,100]になりますが、
app.project.activeItem.selectedLayers[0].position.valueの値は[960,540,0]のままです。

//事前に1920×1080のコンポにヌルを作って、3Dレイヤーにして、それを選択しておく。

//位置情報を変数に入れる。
var mPos = app.project.activeItem.selectedLayers[0].position.value;

//配列の(ゼロから数えて)2番目(つまりZの値)から1つ抜いて、新たに100という数値を足す。
mPos.splice( 2, 1 , 100 );

//下記の結果は[960,540,100]。
alert( mPos );
//下記の結果は[960,540,0]。
alert( app.project.activeItem.selectedLayers[0].position.value );

なぜこのような仕様になっているのでしょうか?
それは、おそらく『setValueメソッド』と関連しているのでしょう。AEのスクリプトでは、valueに直接イコールで値を代入しても値が変更されず、setValueメソッドを使う必要があります。これは、ちょっとした手違いでvalueの値が変わってしまうことがないよう、AEが用意した親切仕様だと思われます。
せっかくsetValueメソッドを用意したのに、変数でvalueを共有すれば簡単に代入できるようになったんでは、メソッドを用意した意味がないですね。ということで、valueは変数に代入した時点でコピーされる仕様になっているのだと思われます。

これを覚えておけば、「位置情報のvalueを変数に入れたのだから、位置プロパティと共有された値なのでは?」と思って、いちいち明示的に

var mPos = app.project.activeItem.selectedLayers[0].position.value;

//sliceメソッドを使った配列のコピー方法(要素もコピーとなる)。
var mPos = mPos.slice();

とか書かなくて大丈夫だとわかりますね!

コピーした配列は「JavaScriptルールに従う」ただの配列になるので、逆に今度は値渡し、参照渡しのルールに気を付けて下さいね。

たいがいのスクリプトはこれで大丈夫なんですが、実はパスプロパティにもvalueがありまして、これの扱いはちょっと複雑なので、次回に書きます。

よかったらシェアしてね!
  • URLをコピーしました!