JavaScriptの即時関数

April 4, 2011
先日twitterでの質問に、ちょろっと修正コードだけ書いて答えたんだけど、その補足。

AfterEffectsでいくつかのスクリプトを使用すると、グローバル変数や関数がコンフリクトを起こすことがあります。
特にAfterEffectsではスクリプトが終了しても、グローバル変数自体はそのままメモリ上に残っているため、現在実行中のスクリプトがなくてもコンフリクトが発生する可能性があります。これらを避けるためにスクリプト自体を即時関数にしてしまうという方法があります。(割と手っ取り早くできてしまうので乱発したくなるかもしれませんが、個人的にはコードの視認性や保守性からあまりオススメしません)

本来はきちんとグローバル変数やグローバル関数の命名を管理して、必要であればオブジェクトのプロパティなどにまとめていくことなどが望ましいのですが、既に使用中のスクリプトにこれらの問題が発生し、早急に対処したい場合には即時関数化することで対処が可能です。

以下のようなコードがあったとします。

var myItem = app.project.item(1);
alert(myItem.name);

これでもかという位に不遜な名前のグローバル変数ですが、これを即時関数化することで変数のスコープをローカル化します。

(function(){
   var myItem = app.project.item(1);
   alert(myItem.name);
}());

これで即時関数化されますので、このmyItemはローカル変数になります。即時関数は、関数自体がコールされなくても定義と同時に実行されますので、普通の逐次コードを即時関数で囲むだけでグローバル変数をローカル変数にできます。この即時関数化は便利なようですが、グローバルオブジェクトのアクセス時に問題になります。AfterEffectsではScript UIなどで「this」としてグローバルオブジェクトを参照するときなどが顕著です。この場合は即時関数の引数にグローバルオブジェクトをまるごと渡してしまい、それを即時関数の自己呼出関数の引数を経由してアクセスすることができます。

(function(global){
   var myPalette = global;
   myPalette.add("statictext",[5,10,100,40],"myPalette");
}(this));

グローバルスコープでのコンフリクトを避けるという意味では、簡単なのですが一見してコードが読み取りにくくメンテナンス性にも問題が出るので、個人的にはあまりお勧めできる方法ではないと思います。一応こんな風にすればグローバルオブジェクトにアクセスできるよ、ということで書いてみました。

オブジェクトも同じように即時化できますが、これはまた別の機会に。