「お手軽エクスプレッションwiggle() で揺らす」で学んだ基本的な関数の記述方法。関数とは、噛み砕くと「引数を変えて同じ処理を使い回す」いわば計算式の公式化と言えます。
変数と同じく、関数も自作できます。
今回の記事で、関数の作り方(定義)を学んでいきましょう。
関数の宣言
変数(var)と同じように、「ここから関数である」と宣言し、関数を定義していきます。「function」です。
// 税抜価格を税込価格に変換する
function f_tax(excluded){
return excluded*1.1;
}
// 関数を定義しただけではなにも処理しない
「function」に続き、「関数名(引数){ 処理内容 }」これが関数の定義です。
関数名…任意の名前。通常、「何を計算する関数か」自分がわかりやすい名前をつけます。筆者は関数名を「f_」に続いて命名する癖があるだけで、ルールではありません。自身のわかりやすい名前で構いません。
引数…関数を使用する(呼び出す)際に値を受け取る受け皿です。今回の関数であれば税抜き価格を、「excluded」という変数で関数内の処理でのみ利用できる値として受け取ります。価格は任意の値を指定できるよう、引数で受け取る形にします。
処理内容…受け取った「excluded」を1.1倍にして税込み価格に計算します。
return…計算結果を関数の外に返します。関数の外側から計算結果が欲しいわけなので、関数の最後には必ずreturnして終わりましょう。
関数の呼び出し方
関数を定義しただけでは、「f_tax」という関数を作っただけで、なにも起こりません。作った関数を呼び出して初めてfunction内の処理が意味を持ちます。
基本的な関数の呼び出し
では、作った関数の使い方です。「関数名+(引数)」で呼び出すことができます。
引数がない、もしくは省略すればデフォルトの値をつかうよう作られた関数は「関数名()」で呼び出せます。
// 税抜価格を税込価格に変換する
function f_tax(excluded){
return excluded*1.1;
}
f_tax(980); // 1078と返ってくる
最後の行で関数を呼び出しています。その際、税抜価格の「980円」を税込価格にしたいので、引数として「980」を渡します。
今回の関数は引数がなければ意味をなしません。引数を忘れると処理内でexcludedが未設定の状態で1.1倍されるので、”NaN”と返ってきます。
“NaN”は「Not-A-Number」の略で、「数字じゃないよ」ということです。
関数を呼び出しながら変数へ
関数を呼び出しながら変数に入れることもできます。
// 税抜価格を税込価格に変換する
function f_tax(excluded){
return excluded*1.1;
}
x=f_tax(980); // 1078
これで変数「x」が1078となります。どうでしょう。様々な使い方が見えてきて目の前が開けてきませんか?
関数を文章に入れ込む
関数を変数にそのまま設定できるということは、関数は現状「1078」と同じ意味を持っているということです。文章中にもそのまま表示できます。
テキストのソーステキストに下記を打ち込んでみましょう。
// 税抜価格を税込価格に変換する
function f_tax(excluded){
return excluded*1.1;
}
"税込価格は"+f_tax(980)+"円です。";
「税込価格は1078円です。」と表示されます。
呼び出し関数を簡潔にしたい場合は、関数内で文章を設定し、
// 税抜価格を税込価格に変換する
function f_tax(excluded){
return "税込価格は"+excluded*1.1+"円です。";
}
f_tax(980);
としても結果は同じです。
スコープの仕様
スコープとは「{}」で囲まれた内側と外側のエリアを区別するための呼び名です。スコープの内側と外側にどのような違いがあるのか、意図しないエラーを防ぐために、またエラーとなった原因に気づくヒントになるよう、知識が必要です。
※2020年現在、ae用に覚えるスコープ グローバルスコープ…プログラムの1階層目。トップ。 └関数スコープ(ローカルスコープ)…functionの「{}」の内側。
また、After Effectsの世界ではまだ対応していませんが、世の中のJavaScriptでは新しい宣言「let」と「const」が使用でき、ブロックスコープという区別が必要になりました。After Effects以外でもJavaScriptを使いたい場合は下記の区別が必要です。
After Effects内でのJavaScriptのみ覚えたい場合は、下記は無視して構いません。こんなルールに変わったんだと頭の片隅にだけ置いておいてください。
※2020年現在、aeでは対応していない新しいJavaScriptでのスコープ グローバルスコープ…プログラムの1階層目。トップ。 └ローカルスコープ…プログラムの2階層目以降。「{}」の内側。 ├関数スコープ…functionの「{}」の内側。 └ブロックスコープ…「let」「const」使用時のfunction以外の「{}」の内側。
スコープ内外での変数宣言
functionの内側を「関数スコープ」と呼び、この中で宣言した変数はスコープ外で使えません。
function f_tax2(excluded){
var txt="税込み価格→";
return excluded*1.1;
}
txt+f_tax2(980); // 「txt」が見つからずエラー
「txt」をスコープ内で宣言しているため、スコープの外側では「txt」がなんのこっちゃわからずエラーを吐きます。
この式でやりたいことは、通常は
var txt="税込み価格→";
function f_tax2(excluded){
return excluded*1.1;
}
txt+f_tax2(980); // 「税込み価格→1078」
「txt」はスコープの外で使いたいのですから、スコープの外で宣言しておけば、正常に動きます。
グローバル変数とローカル変数
メリットとしては、1つのプログラム中に関数を複数扱うようになると、意図せず何度も変数「txt」を使ってしまい、誤って「txt」を上書きしてしまうミスを防止できるわけです。変数の競合を防ぐ役割があります。
デメリットとしては、スコープ内外での変数がごっちゃになると、意図しないエラーが出てしまいます。
スコープの外側で宣言した変数を「グローバル変数」と呼び、宣言後はどこでも使用できます。
スコープの内側で宣言した変数を「ローカル変数」と呼び、宣言したスコープ内でしか使用できません。
このようにスコープの構造を意識してコーディングしていきましょう。
var忘れによるローカル変数のグローバル変数化
ご説明したように、下記の例ではスコープ内で宣言した変数「local」は、スコープ外である最後の行では使えません。
function f_localVar(){
var local="ローカル変数";
return local;
}
f_localVar();
local; // localが見つからずエラー
しかし、スコープ内で宣言「var」を省略すると、グローバル変数として宣言出来てしまいます…。
function f_localVar(){
local="ローカル変数"; // 「var」を省略
return local;
}
f_localVar();
local; // "ローカル変数"と表示される
意図しない書き換えを防ぐためにも、初めの内は基本的に宣言「var」を省略しないよう徹底しましょう。グローバル変数とローカル変数の区別がしっかりと付き、「var」の省略によるローカル変数のグローバル変数化の知識もあり、プログラム全体を管理できる状態に限って、「var」を省略しても意図したように動かせるようになります。
変数の「巻き上げ」現象に注意
JavaScriptでは他のプログラム言語と違う挙動に注意が必要です。変数の「巻き上げ」というエラーに近い仕様です。
// 「巻き上げ」が起こるコード
var txt1="global";
function f_localVar(){
var txt2=txt1;
var txt1="local";
return txt1+" "+txt2;
}
f_localVar();
上記の例では「local global」と表示されると思われたかもしれませんが、実際には「local undefined」です。これが「巻き上げ」です。
関数内で宣言された変数は、どこで宣言されてもその関数の冒頭で宣言される挙動をします。上記のコードは2行目で宣言した「var txt1=”global”」を、6行目で「var txt1=”local”」と再度宣言していますが、実際は仕様により4行目と5行目の間で宣言「だけ」され、6行目で値を代入される、という変な動きをします。
つまり下記のコードとして実行されます。
// 「巻き上げ」時に実際に処理されるコード
var txt1="global";
function f_localVar(){
var txt1; // ここで宣言だけされ、txt1は「undefined」に…
var txt2=txt1; // 「undefined」を代入してしまう
var txt1="local";
return txt1+" "+txt2;
}
f_localVar();
そのため、上記6行目(元の5行目)の「txt2=txt1」では、代入したい値「txt1」が空(undefined)になっており、計算結果は「local undefined」となってしまうのです。
対処法としては簡単で、「変数の再宣言をしない」もしくは「関数内でのローカル変数宣言は、関数の冒頭で行う」ことです。
こちらも「こんな挙動があるんだ」と覚えておくだけで簡単に回避できます。
関数名を省略したい方は「無名関数」
1度しか使わない関数の記述方法「無名関数」方式で関数を記述することもできます。名前を付けるという面倒な手間を省けるメリットがあります。
// 無名関数
var txt = function(x,y){
return x+y;
}
txt(1,2); // 「3」が返ってくる
このように変数に関数を代入し、関数名の代わりに変数名で呼び出します。
呼び出すのも面倒な方は「即時関数」
上記「無名関数」と関連して説明されることの多い「即時関数」。
即時に実行される関数で、呼び出さず、名前も考えずに済み、さらに処理が上述した「関数スコープ」で記述できる為、グローバル変数を汚さないために使われることが多いです。
// 即時関数1
var txt=(function(x,y){
return x+y;
}(3,4));
txt; // 「7」
// 即時関数2
(function(x,y){
return x+y;
}(3,4)); // 「7」が返ってくる
function直後に引数を指定し、function全体を「()」で囲んでしまえば、即時関数となります。
お疲れさまでした
ここまで目次順で、スクリプト記事で追ってきた方は11記事、エクスプレッション記事で追ってきた方は9記事のいわば「JavaScriptの基本編」を完走したことになります。
以上で基本的なJavaScriptの知識が身につきましたので、今後の記事では基本的なコードは細かく説明せず、主に新たに記事内で使用するAfter Effects独自の関数やプロパティの解説のみ行います。
大丈夫です。ここまで来られた方は、ある程度コードを読めるようになっているはずです。あとは単語の意味さえ説明を受ければ、調べながら自身で新しいコードを書けるようになっています。
プログラムは書かなければ覚えられません。是非エクスプレッション、スクリプトへ挑戦して頂き、自身の環境に合った効率化を実現していきましょう。
この記事へのコメントはありません。