関数を作成する方法がもう 1 つあります。めったに使用されませんが、代替手段がない場合もあります。
関数を作成するための構文は次のとおりです。
let func = new Function ([arg1, arg2, ...argN], functionBody);
この関数は、引数arg1...argN
と指定されたfunctionBody
を使用して作成されます。
例を見ると理解しやすいです。これは 2 つの引数を持つ関数です。
let sum = new Function('a', 'b', 'return a + b'); アラート( sum(1, 2) ); // 3
そして、ここには引数のない、関数本体のみを持つ関数があります。
letsayHi = new Function('alert("Hello")'); こんにちは(); // こんにちは
これまで見てきた他の方法との主な違いは、関数が文字通り文字列から作成され、実行時に渡されることです。
これまでのすべての宣言では、プログラマがスクリプト内に関数コードを記述する必要がありました。
しかし、 new Function
と、任意の文字列を関数に変換できます。たとえば、サーバーから新しい関数を受信して実行できます。
let str = ... サーバーからコードを動的に受信します ... let func = new Function(str); 関数();
これは、サーバーからコードを受信する場合や、複雑な Web アプリケーションでテンプレートから関数を動的にコンパイルする場合など、非常に特殊な場合に使用されます。
通常、関数は特別なプロパティ[[Environment]]
のどこで誕生したかを記憶します。これは、それが作成された場所から字句環境を参照します (これについては、変数スコープ、クロージャの章で説明しました)。
ただし、 new Function
を使用して関数が作成されると、その[[Environment]]
現在の語彙環境ではなく、グローバル環境を参照するように設定されます。
したがって、そのような関数は外部変数にはアクセスできず、グローバル変数にのみアクセスできます。
関数 getFunc() { 値 = "テスト"; let func = new Function('alert(value)'); 戻り関数; } getFunc()(); // エラー: 値が定義されていません
通常の動作と比較してください。
関数 getFunc() { 値 = "テスト"; let func = function() {alert(value); }; 戻り関数; } getFunc()(); // getFunc の語彙環境からの "test"
new Function
のこの特別な機能は奇妙に見えますが、実際には非常に便利です。
文字列から関数を作成する必要があると想像してください。その関数のコードは、スクリプトの作成時点では不明ですが (そのため、通常の関数は使用しません)、実行の過程でわかります。サーバーまたは別のソースから受信する場合があります。
新しい関数はメイン スクリプトと対話する必要があります。
外部変数にアクセスできたらどうなるでしょうか?
問題は、JavaScript が運用環境に公開される前に、ミニファイアー (余分なコメントやスペースを削除してコードを縮小する特別なプログラム) を使用して圧縮されることです。そして、重要なことは、ローカル変数の名前を短いものに変更することです。
たとえば、関数にlet userName
がある場合、minifier はそれをlet a
(または、この文字が使用されている場合は別の文字) に置き換え、どこでもそれを実行します。変数はローカルであり、関数の外部からはアクセスできないため、通常はこれを行うのが安全です。そして、関数内では、それに関するすべての記述が minifier に置き換えられます。ミニファイアーは賢く、コード構造を分析するため、何も壊しません。これらは単なる愚かな検索と置換ではありません。
したがって、 new Function
外部変数にアクセスできる場合、名前が変更されたuserName
を見つけることができません。
new Function
外部変数にアクセスできる場合、ミニファイアーで問題が発生します。
さらに、そのようなコードはアーキテクチャ的に悪く、エラーが発生しやすくなります。
new Function
として作成された関数に何かを渡すには、その引数を使用する必要があります。
構文:
let func = new Function ([arg1, arg2, ...argN], functionBody);
歴史的な理由から、引数はカンマ区切りのリストとして指定することもできます。
これら 3 つの宣言は同じ意味です。
new Function('a', 'b', 'return a + b'); // 基本的な構文 new Function('a,b', 'return a + b'); // カンマ区切り new Function('a , b', 'return a + b'); // スペースでカンマ区切り
new Function
で作成された関数には、外部の語彙環境ではなく、グローバルな語彙環境を参照する[[Environment]]
があります。したがって、外部変数は使用できません。しかし、それは間違いを防ぐことができるので、実際には良いことなのです。パラメーターを明示的に渡すことは、アーキテクチャ的にははるかに優れた方法であり、ミニファイアーで問題が発生することはありません。