クロージャは内部関数です。内部関数は、外部関数の変数にアクセスできます。外部関数にアクセスすることで、内部関数にアクセスできます。次の例を参照してください。

function helloTranslator(String helloWord)
{
return function(String name)
{
return "#helloWord#, #name#";
};
}
helloInHindi=helloTranslator("Namaste");
helloInFrench=helloTranslator("Bonjour");
writeoutput(helloInHindi("Anna"));
//closure is formed.
//Prints Namaste, Anna.
writeoutput("<br>");
writeoutput(helloInFrench("John"));
//Prints Bonjour, John.
</cfscript>

この例では、外部関数はクロージャを返します。外部関数には helloHindi 変数を使用してアクセスします。この関数は helloWord 引数を設定します。この関数ポインターを使用して、クロージャを呼び出します。例えば、helloInHindi("Anna") のようにします。外部関数の実行後であっても、クロージャは外部関数によって変数セットにアクセスできることに注意してください。

この場合、クロージャを使用して 2 つの新しい関数が作成されます。1 つは名前に Namaste を追加します。もう 1 つは名前に Bonjour を追加します。helloInHindi および helloInFrench はクロージャです。これらの関数の本文は同じですが、異なる環境を格納します。
内部関数は、外部関数が返った後でも実行できます。内部関数が実行可能な場合に、クロージャが形成されます。
例で示されているように、外部関数から返った後でも、内部関数は外部関数の変数にアクセスできます。クロージャは、作成時の環境への参照を保持しています。例えば、外部関数のローカル変数の値などです。これにより、クロージャは簡単に使用できる便利な機能になります。
クロージャについて詳しくは、http://jibbering.com/faq/notes/closures を参照してください。

ColdFusion でのクロージャ

クロージャは次のようなカテゴリにできます。

  • 名前を指定しないでインラインで定義。次のようにして使用できます。
    • 変数、配列項目、構造体および変数スコープに代入できます。関数から直接返すことができます。 

function operation(string operator)
{
return function(numeric x, numeric y)
{
if(operator eq "add")
{
return x + y;
}
else if(operator eq "subtract")
{
return x - y;
}
};
}
myval_addition=operation("add");
myval_substraction=operation("subtract");
writeoutput(myval_addition(10,20));
writeoutput("<br>");
writeoutput(myval_substraction(10,20));
</cfscript>

この例では、外部関数は演算子を設定します。myval_addition および myval_substraction は 2 つのクロージャです。これらは、外部関数によって設定された条件に基づいてデータを処理します。

  • 関数およびタグ引数としてインラインで定義。

<cfscript>
function operation(numeric x, numeric y, function logic)
{
var result=logic(x,y);
return result;
}
add = operation(10,20, function(numeric N1, numeric N2)
{
return N1+N2;
});
subtract = operation(10,20, function(numeric N1, numeric N2)
{
return N1-N2;
});
</cfscript>
<cfdump var="#add#">
<cfdump var="#subtract#">

この例では、関数 operation の引数 logic がクロージャです。operation を呼び出すとき、インラインクロージャが引数として渡されます。この匿名クロージャには、数値を処理するためのロジックが含まれます(addition または subtraction)。この場合、ロジックは動的であり、クロージャとして関数に渡されます。

クロージャは変数に代入可能

変数にクロージャを代入できます。

var c2 = function () {..}

注意:

変数にクロージャを代入する場合は、スクリプト形式のシンタックスのみがサポートされます。

クロージャは戻り値の型として使用可能

クロージャを戻り値の型として使用できます。

注意:

戻り値の型がクロージャの場合は、Function キーワードの先頭を大文字にすることをお勧めします。

Function function exampleClosure(arg1) 
{ 
	function exampleReturned(innerArg) 
	{ 
		return innerArg + arg1; 
	} 
	/* 
	return a reference to the inner function defined. 
	*/ 
return exampleReturned; 
}

キーと値のペアによるクロージャの呼び出し

関数呼び出しの場合と同じように、キーと値のペアを渡してクロージャを呼び出すことができます。

var c2 = function(arg1, arg1) {..} 
c2(arg1=1, arg2=3);

関数の外でクロージャを変数に代入可能

関数の外で変数にクロージャを代入できます。

hello = function (arg1) 
{ 
	writeoutput("Hello " & arg1); 
}; 
hello("Mark");

引数のコレクションによるクロージャの呼び出し

var c2 = function(arg1, arg1) {..} 
argsColl = structNew(); 
argsColl.arg1= 1; 
argsColl.arg2= 3; 
c2(argumentCollection = argsColl);

クロージャと関数

クロージャは、作成時に認識できるように変数のコピーを保持します。グローバル変数(ColdFusion 固有スコープなど)およびローカル変数(宣言または外部関数のローカルおよび引数スコープを含む)は、クロージャの作成時に保持されます。関数は静的です。
次の表では、定義される方法に基づくクロージャのスコープの詳細を示します。

クロージャが定義される状況 スコープ
CFC 関数内 クロージャ引数スコープ、外側の関数のローカルスコープおよび引数スコープ、this スコープ、変数スコープ、スーパースコープ
CFM 関数内 クロージャ引数スコープ、外側の関数のローカルスコープおよび引数スコープ、this スコープ、変数スコープ、スーパースコープ
関数引数として クロージャ引数スコープ、変数スコープ、this スコープ、スーパースコープ(CFC コンポーネント内で定義されている場合)

クロージャでは、スコープが指定されていない変数の検索順序は次のとおりです。

  1. クロージャのローカルスコープ

  2. クロージャの引数スコープ

  3. 可能な場合は、外部関数のローカルスコープ

  4. 可能な場合は、所有者関数のローカルスコープ

  5. ColdFusion のビルトインスコープ

注意:

クロージャはユーザー定義関数を呼び出せません。これは、クロージャのコンテキストは保持されますが、関数のコンテキストは保持されないためです。これにより、誤った結果になります。例えば、クロージャがキャッシュされた場合、クロージャは後で適切に呼び出して使用できますが、関数は使用できません。

クロージャ関数

クロージャ関数は次のとおりです。

isClosure

説明

クロージャの名前かどうかを調べます。

戻り値

名前をクロージャとして呼び出せる場合は True、呼び出せない場合は False。

カテゴリ

決定関数

isClosure(closureName__)

関連項目

他の決定関数。

履歴

ColdFusion 10:この関数が追加されました。

パラメーター

パラメーター 説明
closureName クロージャの名前です。引用符で囲まないでください。定義されている変数名または関数名でない場合は、エラーになります。

使用方法

クロージャの名前かどうかを判定するには、この関数を使用します。

<cfscript> 
	isClosure(closureName) 
	{ 
	 // do something 
	} 
	else 
	{ 
	 // do something 
	} 
</cfscript>

関数 isCustomFunction に対する変更

クロージャは関数オブジェクトですが、カスタム関数とは見なされません。
関数は次の値を返すようになっています。

  • True:名前をカスタム関数として呼び出せる場合。
  • False:名前をクロージャとして呼び出せる場合。

使用例

次の例では、ColdFusion のクロージャを効果的に使用できる方法を説明します。

例 - クロージャを使用した配列のフィルター処理

次の例では、所在地、年齢、呼称に基づいて従業員をフィルター処理します。フィルター処理には単一の関数を使用します。フィルター処理のロジックは、クロージャとして関数に提供されます。そのフィルター処理ロジックは動的に変更されます。

  1. 変数を定義する employee.cfcfile を作成します。
/** 
* @name employee 
* @displayname ColdFusion Closure Example 
* @output false 
* @accessors true 
*/ 
component 
{ 
property string Name; 
property numeric Age; 
property string designation; 
property string location; 
property string status; 
}
  1. 従業員の配列を作成します。この CFC には filterArray() }} 関数も含まれます。クロージャ {{filter は、関数の引数です。この関数にアクセスするときに、フィルター処理のロジックをクロージャとして渡します。
<!---filter.cfc---> 
<cfcomponent> 
<cfscript> 
//Filter the array based on the logic provided by the closure. 
function filterArray(Array a, function filter) 
	{ 
		resultarray = arraynew(1); 
			for(i=1;i<=ArrayLen(a);i++) 
			{ 
				if(filter(a[i])) 
				ArrayAppend(resultarray,a[i]); 
			} 
		return resultarray; 
	} 
function getEmployee() 
	{ 
//Create the employee array. 
	empArray = Arraynew(1); 
	ArrayAppend(empArray,new employee(Name="Ryan", Age=24, designation="Manager", location="US")); 
	ArrayAppend(empArray,new employee(Name="Ben", Age=34, designation="Sr Manager", 	location="US")); 
	ArrayAppend(empArray,new employee(Name="Den", Age=24, designation="Software Engineer", location="US")); 
	ArrayAppend(empArray,new employee(Name="Ran", Age=28, designation="Manager", location="IND")); 
	ArrayAppend(empArray,new employee(Name="Ramesh", Age=31, designation="Software Engineer", location="IND")); 
	return empArray; 
	} 
</cfscript> 
</cfcomponent>
  1. フィルター処理のロジックを提供するクロージャを指定して {{filterArray()}} 関数にアクセスする CFM ページを作成します。{{filterArray()}} 関数は、従業員データを所在地、年齢、呼称の 3 つの方法でフィルター処理するために使用されます。関数にアクセスするたびに、クロージャ内のフィルター処理ロジックが変更されます。
<!---arrayFilter.cfm---> 
<cfset filteredArray = arraynew(1)> 
<cfset componentArray = [3,6,8,2,4,7,9]> 
<cfscript> 
obj = CreateObject("component", "filter"); 
// Filters employees from India 
filteredArray = obj.filterArray(obj.getEmployee(), function(a) 
	{ 
	if(a.getLocation()=="IND") 
		return 1; 
	else 
		return 0; 
	}); 
writedump(filteredArray); 
//Filters employees from india whos age is above thirty 
filteredArray = obj.filterArray(obj.getEmployee(), closure(a) 
	{ 
	if((a.getLocation()=="IND") && (a.getAge()>30)) 
		return 1; 
	else 
		return 0; 
	}); 
writedump(filteredArray); 
// Filters employees who are managers 
filteredArray = obj.filterArray( obj.getEmployee(), function(a) 
	{ 
	if((a.getdesignation() contains "Manager")) 
		return 1; 
	else 
		return 0; 
	}); 
writedump(filteredArray); 
</cfscript>

タグのクロージャ

以前のバージョンの ColdFusion では、関数ではタグを使用できましたが、タグでは使用できませんでした。タグでクロージャをサポートするということは、CFTag 内部に埋め込まれた CFScript 本文内で有効なものがすべて有効になることを意味します。

例えば、arraySortのクロージャ関数は期待どおりの結果を返します。

<cfscript>
	// Define an array of structs
	myArray = [
    		{name="Thomas", age="22"},
    		{name="Zaza", age="36"},
    		{name="Novak", age="136"},
{name="Marin", age="361"},
    		{name="Rafa", age="03"},
    		{name="$bl0091@", age="-23"}
];

// Define a closure function that sorts the names in the array of structs
callback=function (e1, e2){
    	return compare(e1.name, e2.name);
}

// Use the closure function
arraySort(myArray,callback);

// Display the sorted array of structs
WriteDump(myArray);
</cfscript>

一方、以下のスニペットは常に例外を返します。

<cfset myClosure= function() {…}>

ColdFusion(2018 リリース)では、タグでクロージャ関数を使用できます。次に例を示します。

<cfset myarray=[
    {name="Thomas", age="22"},
    {name="Zaza", age="36"},
    {name="Novak", age="136"},
    {name="Marin", age="361"},
    {name="Rafa", age="3"},
    {name="$bl0091@", age="-23"}
]>
<!--- define closure function --->
<cfset closure=function (e1,e2){
	return compare(e1.name,e2.name);
}>
<cfset ar = arraySort(myarray,closure)>
<cfdump var="#myarray#">

本作品は Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License によってライセンス許可を受けています。  Twitter™ および Facebook の投稿には、Creative Commons の規約内容は適用されません。

法律上の注意   |   プライバシーポリシー