eval()とnew Function()は同じものですか?


89

これら2つの関数は裏で同じことをしていますか?(単一ステートメント関数内)

var evaluate = function(string) {
    return eval('(' + string + ')');
}

var func = function(string) {
    return (new Function( 'return (' + string + ')' )());
}

console.log(evaluate('2 + 1'));
console.log(func('2 + 1'));

3
実際、これはjQuery 1.7.2の573行目で使用されています。「一部のセキュリティチェック」を使用していますが、
PicoCreatorは

2
newこの議論でなぜ考慮されるのですか?Function暗黙的にをインスタンス化しfunction objectます。除外しnewてもコードはまったく変わりません。これがjsfiddleのデモです:jsfiddle.net/PcfG8
Travis J

回答:


114

いや、彼らはありません同じ。

  • eval() 文字列を現在の実行スコープ内のJavaScript式として評価し、ローカル変数にアクセスできます。
  • new Function()文字列に格納されたJavaScriptコードを関数オブジェクトに解析し、それを呼び出すことができます。コードが別のスコープで実行されるため、ローカル変数にアクセスできません。

このコードを考えてみましょう:

function test1() {
    var a = 11;
    eval('(a = 22)');
    alert(a);            // alerts 22
}

場合new Function('return (a = 22);')()に使用された、ローカル変数は、aその値を維持するだろう。それでも、Douglas Crockfordなどの一部のJavaScriptプログラマーは、絶対に必要でない限りどちらも使用すべきではないと信じており信頼できないデータでコンストラクターを評価/使用することは安全でなく、賢明ではありません。Function


10
「絶対に使用してはならない」というのは、このように広い表現です。どのようにしたら、入力のいずれかがあなたのコントロールの外にあるとき、決して使われるべきではありません。そうは言っても、JSONの解析を除いて、それを使用する必要はありませんでした。しかし、ここでは有効な使用のように見える質問に回答しました。エンドユーザーが使用できるテンプレート関数を管理者が生成できるようにするようなものです。この場合、入力は管理者によって生成されたため、許容可能でした
フアンメンデス

3
@Juan:Crockfordのポイントは、evalは誤用されることが多いため(見方によって異なります)、「ベストプラクティス」JavaScriptから除外する必要があります。ただし、入力が最初に適切に検証されるときに、JSONや算術式の解析などの用途に役立つことにも同意します。Crockfordでさえ、JSONライブラリjson2.jsで使用しています。
PleaseStand

つまり、これはnew Function(code)同じであるeval('(function(){'+code+'})()')か、まったく新しい実行コンテキストなのでしょうか。
George Mauer

5
@GeorgeMauer:つまりeval('(function(){'+code+'})')、関数オブジェクトを返すと思います。MDNよれば、「Functionコンストラクターで作成された関数は、作成コンテキストにクロージャーを作成しません。それらは常にウィンドウコンテキストで実行されます(関数本体が「use strict」で始まる場合を除く)。この場合、コンテキストは未定義です) 」
PleaseStand

6

番号。

更新では、を呼び出して同じ結果evaluatefunc生成します。しかし、彼らは間違いなく「裏で同じことをしている」わけではありません。このfunc関数は新しい関数を作成しますが、すぐに実行しますが、evaluate関数はその場でコードを実行するだけです。

元の質問から:

var evaluate = function(string) {
    return eval(string);
}
var func = function(string) {
    return (new Function( 'return (' + string + ')' )());
}

これらはあなたに非常に異なる結果を与えます:

evaluate('0) + (4');
func('0) + (4');

いずれにせよ、最も例外的なケースを除いて、両方とも悪い習慣です。
palswim 2011年

8
さて、あなたは彼の実装に従ってあなたの例をごまかしました。彼が実装したreturn eval('(' + string + ')');場合、同じ結果が得られるのと同じように評価しました。
ファンメンデス

@Juan思っていなかったけどね。質問を編集しました
qwertymk

6

new Function 再利用可能な関数を作成します。 eval与えられた文字列を実行し、最後のステートメントの結果を返すだけです。Functionを使用してevalをエミュレートするラッパー関数を作成しようとしたため、あなたの質問は見当違いです。

彼らがカーテンの後ろでいくつかのコードを共有しているのは本当ですか?はい、そうです。まったく同じコードですか?いいえ、確かに。

楽しみのために、関数を作成するためにevalを使用する私の独自の不完全な実装を示します。それが違いを明らかにすることを願っています!

function makeFunction() {
  var params = [];
  for (var i = 0; i < arguments.length -  1; i++) {
    params.push(arguments[i]);
  }
  var code = arguments[arguments.length -  1];


 // Creates the anonymous function to be returned
 // The following line doesn't work in IE
 // return eval('(function (' + params.join(',')+ '){' + code + '})');
 // This does though
 return eval('[function (' + params.join(',')+ '){' + code + '}][0]');
}

この関数と新しい関数の最大の違いは、関数がレキシカルスコープではないことです。したがって、クロージャー変数にアクセスすることはできません。


arguments.slice()forループの代わりに使用しないのはなぜですか?または引数ならば、真の配列ではありません[].slice.call(arguments, 1)
Xeoncross 2014

3

ここの例で使用されている構文とその意味を指摘したいだけです。

 var func = function(string) {
     return (new Function( 'return (' + string + ')' )());
 }

Function(...)()の最後に「()」があることに注意してください。この構文により、funcは新しい関数を実行し、文字列を返す関数ではなく文字列を返しますが、以下を使用すると、

 var func = function(string) {
     return (new Function( 'return (' + string + ')' ));
 }

funcは文字列を返す関数を返します。


2

つまり、同じ結果が得られますか?はい...しかし、単にeval(「JavaScriptのこの文字列を評価する」)のほうがはるかに簡単です。

以下を編集:

それは言うようなものです...これらの2つの数学の問題は同じですか?

1 + 1

1 + 1 + 1-1 + 1-1 * 1/1


彼らは両方とも文字列を再解析しますか?
qwertymk '05年

どちらも(コード例では)文字列を解析します。「再解析」の意味がわからない。
Timothy Khouri、2011年

1
きっとどちらもある時点で文字列を解析(評価)するはずですが、関数を呼び出すと、Functionオブジェクトはおそらく文字列をプライベートメンバー変数に格納しますeval
palswim、2011年

1

その例では、結果は同じです。どちらも渡した式を実行します。これが彼らをとても危険にしているものです。

しかし、彼らは舞台裏でさまざまなことをします。を含むものはnew Function()、舞台裏で、指定されたコードから匿名関数を作成し、関数が呼び出されたときに実行されます。

渡されたJavaScriptは、匿名関数を呼び出すまで技術的には実行されません。これはeval()、コードをすぐに実行し、それに基づいて関数を生成しないのとは対照的です。


もう少し詳しく説明してもらえますか?どちらもreturnステートメントで実行されていませんか?Function()はeval以外のスタック呼び出しレベルを使用しますか?
qwertymk '05年

Does the Function() one use another stack call level than eval?eval()入力から関数を作成するのではなく、実行するだけなので、そうだと思います。new Function()新しい関数を作成し、それを呼び出します。
Chris Laplante、2011年

@SimpleCoder:Function()は呼び出しスタックに何も追加しません。結果の関数を呼び出す場合のみ。evalはまったく同じことを行います(質問のコンテキストで適用された場合)
Juan Mendes
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.