見出し画像

Velo 第61回 クロージャ

Velo を使ったコーディングでは、CMSやエレメントなど既に出来上がったオブジェクトが持つ値の受け渡しが殆どです。
従ってクラスやクロージャを意識したコーディングは殆どありません。

クロージャでは変数のスコープが問題になりますが、Veloでは例えばページ内でグローバルに使う変数が欲しいときや、ページ遷移を伴う場合にページ内の変数を保持したいときには session など wix-storage を使うので困ることはありません。

とは言え、クロージャは変数のスコープの理解を伴いますので知っておくとコーディングがスムーズになります。
またそれ程難しい話でもありません。
「表立って使わないけど知っておいた方がよい」そういうものと思えばいいと思います。

クロージャ

関数を定義すると、その式だけではなく使える変数も同時に定義され、それらの組み合わせが保存されます。これをクロージャと言います。ですので関数を定義するとクロージャが定義されます。

変数のスコープはソースコードに出てきた階層順で決まります。
以下のコードで確かめてみましょう。

変数のスコープ

func_a 関数から見える変数は variable と variable_a です。variable_b は見えません。同様に func_b 関数から見える変数は variable と variable_b です。variable_a は見えません。
つまり関数から見える変数はその関数の内と外にある変数で、他の関数の内の変数は見えません。

変数 variable は2つの関数の外にありますので、どちらの関数のスコープにも入り、どちらの関数からも利用できます。
func_a を実行すると variable がインクリメントされ、func_b を実行すると variable がデクリメントされます。
つまり variable はグローバル変数になっています。

これは便利でいいことでもありますが、一方、どの関数からもアクセス出来たり、変数のバッティングが起こったりする副作用も気になるところです。例えば func_a だけに使える変数を作ることはできないのでしょうか?

変数のスコープをクロージャで制御する

func_a にだけ使えて他の関数には使えない変数を作るには func_aと同じ階層に変数を作り、その階層を別の関数に入れて他の関数から見えなくしてしまえばいいことになります。以下のコードで確かめましょう。

クロージャ

3行目の変数 variable_func_a は4行目で定義される関数 func_a の外にあるので func_a から見えます。従って5行目でその値に1を加えた値をコンソールに表示することが可能です。

関数 returnfunc_a の役割

さて1行目で定義した関数 returnfunc_a の戻り値は注意しなければいけません。それは7行目の func_a で、これはfunc_a( )とは異なります。
つまり4行目で定義した関数の実行結果ではなく、そのアドレスを戻します。
従って returnfunc_a を実行すると variable_func_a の値が 0 に初期化され、func_a のアドレスを得ることになります。
ここは難しいと感じるところです。

そして10行目で、returnfunc_a( )を実行させて variable_func_a の値を 0 に初期化し、4行目の関数 func_a のアドレスを新たに func_a で定数化しています。
10行目の定数名は func_a 以外の名前でも構いませんが、同じ名前でも構いません。

関数 func_a( ) の実行

10行目は定数なので関数ではないと思うかも知れませんが、この定数は4行目で定義した関数 func_a のアドレスを表す定数です。
それは関数の名前も同じ役割ですから、結局4行目の func_a も10行目の func_a も同じ関数のアドレスを保持しています。
つまり実行すれば同じ結果になります。従って func_a( ) は実行するたびに1つずつ増える値をコンソールに表示します。

実行結果

以下の様にボタン(button1)のクリックイベントでこの関数を実行させてみましょう。

ボタンのクリックイベントに登録

ボタンを押すたびにコンソールには以下の表示が行われます。

func_a( ) の実行結果(4回分)

オブジェクトへの応用

戻り値をオブジェクトにすることで、同じ変数を扱う2つの関数を作り、このオブジェクトのメソッドにすることも可能です。以下のCounter()関数を実行すると変数 counter の値を1増やす inc、1減らす dec をメソッドに持つカウンターオブジェクトを作ることが出来ます。

カウンターオブジェクト

10行目の2つのオブジェクト a, b は、それぞれ別にカウンター関数を呼び出した結果ですので内部の変数 counter も異なります。つまり全く別のカウンターオブジェクトを作っています。実行結果は以下の通りです。

実行結果

Velo開発のご依頼はこちら

いいなと思ったら応援しよう!