(1、eval)( 'this')vs eval( 'this')in JavaScript?


85

JavaScriptパターンを読み始めましたが、いくつかのコードで混乱しました。

var global = (function () {
    return this || (1, eval)('this');
}());

これが私の質問です:

Q1:

(1, eval) === eval

なぜ、どのように機能するのですか?

Q2:なぜ

var global = (function () {
    return this || eval('this');
}());

または

 var global = (function () {
    return this;
}());

これは特定のケースであるため、タイトルを更新しました。また、括弧内の特定の種類の括弧[]と{}は完全に異なっている:):

回答:


104

(1,eval)とプレーンオールドの違いevalは、前者は値であり、後者は左辺値であるということです。それが他の識別子である場合は、より明白になります。

var x;
x = 1;
(1, x) = 1; //  syntax error, of course!

それは(言うように、またはそうするように)(1,eval)降伏する式ですが、それはへの参照ではありませんeval(true && eval)(0 ? 0 : eval)eval

なんで気にするの?

まあ、Ecmaの仕様は考えて参照するにはeval、「直接evalの呼び出し」を可能にするが、表現のことを単に利回りeval間接評価呼び出しになる式は、グローバルスコープで実行されることが保証されています。

私がまだ知らないこと:

  1. 直接評価呼び出しがグローバルスコープで実行されないのはどのような状況ですか?
  2. どのような状況thisで、グローバルスコープの関数がグローバルオブジェクトを生成できないのでしょうか。

ここでさらにいくつかの情報を収集できます

編集

どうやら、私の最初の質問に対する答えは、「ほとんど常に」です。直接eval現在のスコープから実行されます。次のコードについて考えてみます。

var x = 'outer';
(function() {
  var x = 'inner';
  eval('console.log("direct call: " + x)'); 
  (1,eval)('console.log("indirect call: " + x)'); 
})();

当然のことながら(heh-heh)、これは次のように出力されます。

direct call: inner
indirect call: outer

編集

さらに実験を重ねた後、暫定的thisnullまたはに設定できないと言いundefinedます。他の偽の値(0、 ''、NaN、false)に設定できますが、非常に限られています意図的なものに。

私はあなたの情報源が穏やかで可逆的な頭蓋直腸の反転に苦しんでいると言うつもりであり、ハスケルで1週間のプログラミングを過ごすことを検討したいかもしれません。


3
うわー、全体value対事を知りませんでしたlvalue(まあ、実際には多分、しかし言葉ではありません)。ES5の評価ルールもありません(合理的に使用する必要があるわけではありませんeval)。ありがとう!
ストイブ2012

ええ、eval厄介な鋭いエッジがたくさんあるので、最後の手段としてのみ使用し、次に非常に慎重に使用する必要があります。
マルヴォーリオ2012

私は一度だけ有効な使用法に出くわしましたinnerHtml
-DOMに

1
lvalueは通常、代入の左側に表示される式を参照するため、直接評価を決定することにほとんど関係がありません。したがって、rvalueではなくlvalueという名前になります。evalの呼び出しは、識別子evalがCallExpressionのMemberExpression部分であり、標準eval関数を参照する必要があるという仕様の15.1.2.1.1にリストされている条件下でのみ直接行われます。
chuckj

1
@Malvolio左辺値は、直接評価と間接評価とは関係がないことを示唆しているようです。eval呼び出し式のターゲットとして呼び出される識別子の使用は特別です。あなたは、ECMAが特別なものへの言及を扱っevalていないことを述べています。式が標準eval関数に評価されるのは、特別な呼び出し式の配置です。例えば、var eval = window.eval; eval('1');はまだ直接評価でありwindow.eval('1')、この場合もevalが左辺値であってもそうではありません。
chuckj

33

フラグメント、

var global = (function () {  
    return this || (1, eval)('this');  
}());  

strictモードでもグローバルオブジェクトに正しく評価されます。非厳密モードでは、の値thisはグローバルオブジェクトですが、厳密モードではの値はundefinedです。式(1, eval)('this')は常にグローバルオブジェクトになります。この理由には、間接的なものと直接的なものに関する規則が含まれますeval。への直接呼び出しにevalは呼び出し元のスコープがあり、文字列thisthisクロージャ内のの値に評価されます。間接evalは、グローバルスコープ内の関数内で実行されたかのように、グローバルスコープ内で評価されます。その関数自体は厳密モード関数ではないため、グローバルオブジェクトはとして渡されthis、式'this'はグローバルオブジェクトに評価されます。この表現(1, eval)は、強制するための空想的な方法です。eval 間接的であり、グローバルオブジェクトを返します。

A1:への間接呼び出しと直接呼び出しに関する特別な規則があるためと(1, eval)('this')同じではありません。eval('this')eval

A2:オリジナルはストリクトモードで動作しますが、変更されたバージョンは動作しません。


12

Q1へ:

これはJSのコンマ演算子の良い例だと思います。この記事のコンマ演算子の説明が好きです:http//javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/

コンマ演算子は、両方のオペランド(左から右)を評価し、2番目のオペランドの値を返します。

Q2へ:

(1, eval)('this')ES5ではコードをグローバルに実行する間接評価呼び出しと見なされます。したがって、結果はグローバルコンテキストになります。

http://perfectionkills.com/global-eval-what-are-the-options/#evaling_in_global_scopeを参照してください


7

Q1:コンマで区切られた複数の連続するjavascriptステートメントは、最後のステートメントの値を取ります。そう:

(1, eval)関数へのeval()関数参照である最後の値を取ります。eval()ES5のグローバルスコープで評価される間接評価呼び出しに呼び出しを行うのは、明らかにこの方法です。詳細はこちらで説明します

Q2:グローバルを定義していないいくつかの環境が存在する必要がありthisますが、定義されませんeval('this')。それが私がそのために考えることができる唯一の理由です。


おそらく誰かが許可しないチェックインフックをかわそうとしているのでしょうか/eval\(/g
ストイブ2012

@ Stoive-ええ、私もそのようなことについて疑問に思いました。チェックインフックでない場合は、プロセスのどこかでフィルターをかけます(おそらく最小化)。
jfriend00 2012

7
これはES5の厳密モードと関係があります。ES5 strictモードでのAFAIKはeval、グローバルコンテキストやそれを囲むコンテキストではなく、独自のコンテキストでコードが実行されます。これを回避する1つの方法は、問題のコードのように間接的に参照することです。
クリスティアンサンチェス


CDSanchezと@Saxoierからの情報を含むように私の答えを更新しました。どうも。
jfriend00 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.