(1, eval) ( 'this') 대 eval ( 'this') JavaScript에서?


85

JavaScript Patterns 를 읽기 시작 했는데 일부 코드가 혼란 스러웠습니다.

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은 전자는 이고 후자는 lvalue라는 것입니다. 다른 식별자라면 더 분명 할 것입니다.

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

그것은 (말 하거나 할 것 같은) (1,eval)양보하는 표현 이지만 .eval(true && eval)(0 ? 0 : eval)eval

왜 신경 쓰나요?

Ecma 사양은 참조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)으로 설정할 수 있지만 매우 고의적으로 만 설정할 수 있습니다 .

나는 당신의 소스가 경미하고 가역적 인 두개-직장 반전으로 고통 받고 있으며 Haskell에서 일주일 동안 프로그래밍하는 것을 고려하고 싶을 것입니다.


3
와우, 전체 valuelvalue일을 몰랐습니다 (실제로는 아마도 말로는 아니지만). ES5 평가 규칙도 아닙니다 (합리적으로 사용해야하는 것은 아닙니다 eval). 감사!
Stoive

예, eval날카로운 모서리가 많기 때문에 최후의 수단으로 만 사용하고 매우 조심스럽게 사용해야합니다.
Malvolio 2012

나는 한 번만 유효한 사용을 발견했습니다 innerHtml
-DOM

1
lvalue는 일반적으로 할당의 왼쪽에 나타날 수있는 표현식을 참조하기 때문에 직접 평가를 결정할 때 거의 기한이 없습니다. 따라서 이름은 rvalue와 반대입니다. eval에 대한 호출은 식별자가 evalCallExpression의 MemberExpression 부분 이어야하며 표준 eval함수를 참조 해야한다는 사양의 15.1.2.1.1에 나열된 조건에서만 직접적 입니다.
chuckj

1
@Malvolio 당신은 lvalues가 직접 대 간접 평가와 관련이 있다는 것을 암시하는 것 같습니다. eval호출 식의 대상으로 호출되는 식별자의 사용 은 특별합니다. ECMA는 그렇지 않은 특수에 대한 참조 를 처리한다고 진술합니다 eval. 표현식이 표준 eval함수로 평가되는 것은 특별한 호출 표현식의 배치입니다 . 예를 들어, var eval = window.eval; eval('1');은 여전히 ​​직접 평가이며 window.eval('1')eval이이 경우에도 lvalue이더라도 그렇지 않습니다.
chuckj

33

조각,

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

엄격 모드에서도 전역 개체를 올바르게 평가합니다. 엄격하지 않은 모드에서의 값은 this전역 개체이지만 엄격 모드에서는입니다 undefined. 식은 (1, eval)('this')항상 전역 개체가됩니다. 그 이유는 간접적 구절에 대한 규칙을 포함합니다 eval. 에 대한 직접 호출 eval은 호출자의 범위 를 가지며 문자열 thisthis클로저 의 값으로 평가됩니다 . 간접 eval은 전역 범위의 함수 내에서 실행 된 것처럼 전역 범위에서 평가됩니다. 이 함수는 그 자체가 엄격 모드 함수가 아니기 때문에 전역 객체는 as로 전달되고 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/

쉼표 연산자는 두 피연산자 (왼쪽에서 오른쪽으로)를 모두 평가하고 두 번째 피연산자의 값을 반환합니다.

Q2 :

(1, eval)('this')간접 평가 호출로 간주되며 ES5에서는 전역 적으로 코드를 실행합니다. 따라서 결과는 글로벌 컨텍스트가 될 것입니다.

http://perfectionkills.com/global-eval-what-are-the-options/#evaling_in_global_scope 참조


7

Q1 : 쉼표로 구분 된 여러 연속 자바 스크립트 문이 마지막 문 값을 사용합니다. 그래서:

(1, eval)함수에 대한 함수 참조 인 마지막 값을받습니다 eval(). eval()ES5의 전역 범위에서 평가 될 간접 평가 호출로 호출 을 만들기 위해 분명히 이런 방식으로 수행됩니다 . 자세한 내용은 여기에 설명되어 있습니다 .

Q2 : 글로벌을 정의하지 않는 몇 가지 환경이 있어야 this하지만, 정의 않습니다 eval('this'). 그것이 내가 그것을 생각할 수있는 유일한 이유입니다.


누군가가 허용하지 않는 체크인 후크를 피하려고 할 수 /eval\(/g있습니까?
Stoive

@Stoive-그래 나도 그런 것에 대해 궁금해했다. 체크인 후크가 아닌 경우 프로세스 어딘가에 필터가 있습니다 (최소화).
jfriend00 2012

7
ES5 엄격 모드와 관련이 있습니다. ES5 엄격 모드의 AFAIK 모든 eval'd 코드는 전역 컨텍스트 또는 둘러싸는 컨텍스트가 아닌 자체 컨텍스트에서 실행됩니다. 이 문제를 해결하는 한 가지 방법은 문제의 코드가하는 것처럼 간접적으로 참조하는 것입니다.
Cristian Sanchez 2012


CDSanchez 및 @Saxoier의 정보를 포함하도록 내 답변을 업데이트했습니다. 고마워.
jfriend00 2012
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.