Javascript (글로벌 변수 포함)의 변수 선언 구문의 차이점은 무엇입니까?


292

변수 선언 사이에 차이점이 있습니까?

var a=0; //1

...이 방법:

a=0; //2

...또는:

window.a=0; //3

글로벌 범위에서?


2
AFAIK var a = 0; 다른 js 파일에 선언 된 다른 외부 js 파일을 통해 변수에 액세스 할 때 IE에서 작동하지 않음
Aivan Monceller

나는 window.a에 대해 모른다. 그러나 다른 두 가지 방법은 전역 범위에서 동일하다.
프로그래머

1
@AivanMonceller 정말? 연결하십시오.
Raynos 2013

@ Raynos, 내 웹 사이트에서 경험합니다. 구체적으로 IE6. 외부 js 파일에있는 var enum을 표시 할 수 없으며 html 파일에서 인라인 자바 스크립트로 참조하고 있습니다
Aivan Monceller

@Ashwini 전역 범위에서 window는 전역 개체 (브라우저)입니다. var a = 1; console.log (a); console.log (win
leebriggs

답변:


557

그렇습니다. 몇 가지 차이점이 있지만 실제로는 큰 차이가 없습니다.

네 번째 방법이 있으며 ES2015 (ES6) 기준으로 두 가지가 더 있습니다. 마지막에 네 번째 방법을 추가했지만 # 1 뒤에 ES2015 방법을 삽입 했으므로 이유를 알 수 있습니다.

var a = 0;     // 1
let a = 0;     // 1.1 (new with ES2015)
const a = 0;   // 1.2 (new with ES2015)
a = 0;         // 2
window.a = 0;  // 3
this.a = 0;    // 4

그 진술은 설명했다

#1 var a = 0;

이것은 또한의 한 속성입니다 전역 변수 생성 전역 객체 우리가 접근, window브라우저에서을 (또는 통해 this비 엄격한 코드의 글로벌 범위). 다른 속성과 달리 속성을 통해 제거 할 수 없습니다 delete.

사양 측면에서, 그것은 생성 바인딩 식별자 상의 객체 환경 기록 에 대한 지구 환경을 . 전역 객체는 전역 환경의 객체 환경 레코드에 대한 식별자 바인딩이 유지되는 위치이므로 전역 객체의 속성이됩니다. 이것이 속성이 삭제 불가능한 이유입니다. 단순한 속성이 아니라 식별자 바인딩입니다.

바인딩 (변수)은 첫 번째 코드 행이 실행되기 전에 정의됩니다 (아래의 "언제 var발생"참조).

주에 생성 된 속성은 IE8에 이전하는 것이 window아닙니다 열거 (에 표시되지 않는 for..in문). IE9, Chrome, Firefox 및 Opera에서는 열거 가능합니다.


# 1.1 let a = 0;

이것은 전역 객체의 속성 이 아닌 전역 변수를 만듭니다 . 이것은 ES2015에서 새로운 것입니다.

스펙 용어로, 환경 레코드 오브젝트가 아닌 글로벌 환경 에 대한 선언적 환경 레코드 에서 ID 바인딩을 작성합니다 . 글로벌 환경은 분할 환경 기록, 글로벌 객체 (이게 오래된 물건 모두를위한 하나의 필요에 고유 한 개체 새로운 물건 모두를위한 환경 기록) 및 다른 ( , ,과에 의해 생성 된 기능 )하지 전역 객체로 이동하십시오.letconstclass

바인딩 생성 포위 블록의 모든 단계별 코드 (전역 코드가 실행되기 전에,이 경우)을 실행하기 전에, 그러나 아니다 접근 단계별 실행이 도달 할 때까지 어떤 방법으로 let문을. 실행이 let명령문에 도달하면 변수에 액세스 할 수 있습니다. ( "참조 letconst아래 발생".)


# 1.2 const a = 0;

글로벌 상수를 작성합니다. 글로벌 상수는 글로벌 오브젝트의 특성이 아닙니다.

const정확히처럼 let당신이 초기화합니다 (제공해야한다는 점을 제외하고 = value일부)하고,이 생성 된 후에는 당신이 상수의 값을 변경할 수 없습니다. 표지 아래에서 let와 동일 하지만 식별자 바인딩에 값을 변경할 수 없다는 플래그가 있습니다. 사용 const은 세 가지 일을합니다.

  1. 상수에 할당하려고하면 구문 분석 시간 오류가 발생합니다.
  2. 다른 프로그래머에게 변하지 않는 특성을 문서화합니다.
  3. JavaScript 엔진이 변경되지 않는 것을 기반으로 최적화하도록합니다.

# 2 a = 0;

이것은 전역 객체에 대한 속성을 암시 적 으로 만듭니다 . 일반적인 속성이므로 삭제할 수 있습니다. 나는 이것을 하지 않는 것이 좋습니다 . 나중에 코드를 읽는 사람에게는 분명하지 않을 수 있습니다. ES5의 엄격 모드를 사용하는 경우, 존재하지 않는 변수에 할당하는 것은 오류입니다. 엄격 모드를 사용하는 몇 가지 이유 중 하나입니다.

그리고 흥미롭게도 IE8 및 이전 버전에서는 속성을 열거 할 수 없습니다 ( for..in구문 에는 표시되지 않음 ). 특히 아래 # 3에 나오는 것은 이상합니다.


#삼 window.a = 0;

이렇게하면 전역 객체 window를 참조 하는 전역을 사용하여 전역 객체에 대한 속성이 명시 적으로 생성 됩니다 (브라우저에서, 브라우저가 아닌 일부 환경에는 globalNodeJS 와 같은 전역 변수가 있습니다 ). 일반적인 속성이므로 삭제할 수 있습니다.

이 속성 IE8 및 이전 버전과 내가 시도한 다른 모든 브라우저에서 열거 가능합니다.


# 4 this.a = 0;

global this대신에 전역 객체를 참조한다는 점을 제외하고는 # 3과 정확히 같습니다 window. 엄격 모드 전역 코드에서는 this전역 객체에 대한 참조가 없기 때문에 엄격 모드에서는 작동하지 않습니다 ( undefined대신 값이 있음 ).


속성 삭제

"삭제"또는 "제거"는 무엇을 의미 a합니까? 정확히 : delete키워드 를 통해 속성을 완전히 제거하십시오 .

window.a = 0;
display("'a' in window? " + ('a' in window)); // displays "true"
delete window.a;
display("'a' in window? " + ('a' in window)); // displays "false"

delete객체에서 속성을 완전히 제거합니다. 당신은 속성에 추가로 그렇게 할 수 없습니다 window를 통해 간접적으로 var는이 delete중 하나를 자동으로 무시하거나 (자바 스크립트 구현에 당신이 엄격 모드에있어 여부에 따라) 예외가 발생합니다.

경고 : IE8 다시 (그리고 아마도 이전 버전과 깨진 "호환성"모드에서 IE9-IE11) : window허용되어 있어도 객체의 속성을 삭제할 수 없습니다 . 더 나쁜 것은 IE8 및 다른 브라우저 에서이 실험 을 시도 하면 예외가 발생합니다 . 따라서 객체 에서 삭제할 때는 방어 적이어야합니다.window

try {
    delete window.prop;
}
catch (e) {
    window.prop = undefined;
}

속성을 삭제하려고 시도하고 예외가 발생하면 다음으로 최선을 다하고 속성을로 설정합니다 undefined.

이것은 객체 에만 적용되며 windowIE8 및 이전 버전 (또는 깨진 "호환성"모드의 IE9-IE11) 에만 적용됩니다 . 다른 브라우저는 window위 규칙에 따라 속성 을 삭제 해도됩니다.


var발생

비아 정의 된 변수 var전에 문은 생성 된 모든 실행 컨텍스트에서 단계별로 코드가 실행되고, 그래서 속성이 아니라 존재 하기 전에var 문.

혼란 스러울 수 있으므로 살펴 보겠습니다.

display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo);          // displays "undefined"
display("bar in window? " + ('bar' in window)); // displays "false"
display("window.bar = " + window.bar);          // displays "undefined"
var foo = "f";
bar = "b";
display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo);          // displays "f"
display("bar in window? " + ('bar' in window)); // displays "true"
display("window.bar = " + window.bar);          // displays "b"

라이브 예 :

보다시피, 심볼 foo은 첫 번째 라인 전에 정의되지만 심볼 bar은 그렇지 않습니다. 를 Where var foo = "f";문이 두 가지 정말이 있습니다 : 실행되는 코드의 첫 번째 행 앞에 일어나는 기호, 정의는; 및 라인이 단계별 흐름 내에있는 경우, 그 심볼에 할당을 수행하는 단계를 포함한다. 파트가 스코프 상단으로 이동 ( " var호이 스팅" var foo) 되었으나 foo = "f"파트가 원래 위치에 남아 있기 때문에 " 게양"이라고합니다 . ( 빈약 한 작은 블로그에서 잘못 이해var가난한 사람을 참조하십시오 .)


언제 let그리고 const어떻게

letconst는 다른 var몇 가지 방법입니다. 질문과 관련된 방법은 정의한 바인딩이 단계별 코드가 실행되기 전에 생성되지만 또는 문에 도달 때까지 액세스 할 수 없다는 것 입니다.letconst

그래서 이것이 실행되는 동안 :

display(a);    // undefined
var a = 0;
display(a);    // 0

오류가 발생합니다.

display(a);    // ReferenceError: a is not defined
let a = 0;
display(a);

다른 두 가지 방법이 있는지 let와는 const다를 var질문에 정말 관련이없는 어떤이다 :

  1. var항상 (글로벌 코드 전체에, 또는이 표시되는 기능에 기능 코드를 통해) 전체 실행 컨텍스트에 적용되지만 letconst단지 내에서 적용 블록 들이 나타납니다. 즉, var함수 (또는 글로벌) 범위를 갖지만, letconst블록의 범위를 갖는다.

  2. var a동일한 컨텍스트에서 반복 하는 것은 무해하지만 let a(또는 const a) let aconst a있거나 다른 또는 a 또는 a var a가있는 경우 구문 오류입니다.

여기에 있음을 보여주는 예입니다 letconst그 블록이 실행 내에서 코드 전에 블록에 즉시 적용되지만까지 액세스 할 수 없습니다 let또는 const문 :

var a = 0;
console.log(a);
if (true)
{
  console.log(a); // ReferenceError: a is not defined
  let a = 1;
  console.log(a);
}

두 번째 는 블록 외부에서 console.log액세스하는 대신 실패합니다 a.


주제 외 : 전체 객체를 어지럽히 지 마십시오 ( window)

window객체는 매우 속성 어수선하게됩니다. 가능하면 혼란에 추가하지 않는 것이 좋습니다. 대신에 약간의 패키지와 수출에 문자를 마무리 가장 받는 하나의 기호 window객체입니다. (나는 자주 내 보내지 않습니다 어떤 받는 문자 window당신은 당신의 문자하기 위해 모든 코드를 포함하는 함수를 사용할 수 있습니다. 개체), 그리고이 마음에 그 기능은 익명으로 할 수 있습니다 :

(function() {
    var a = 0; // `a` is NOT a property of `window` now

    function foo() {
        alert(a);   // Alerts "0", because `foo` can access `a`
    }
})();

이 예에서는 함수를 정의하고 바로 ()끝까지 실행 합니다.

이런 방식으로 사용되는 함수를 범위 지정 함수 라고 합니다 . 범위 지정 함수 내에 정의 된 함수는 해당 데이터에 대한 폐쇄 이기 때문에 범위 지정 함수에 정의 된 변수에 액세스 할 수 있습니다 ( 폐쇄는 빈약 한 블로그에서 복잡하지 않습니다)를 참조하십시오 .


내가 할 수있는 window['a']=0이 내가지도로 창을 사용하고 취소 할 수 있나요? 입니다 window일부 브라우저는이를 허용하고 사용하라고 강요하지 않는 특별 window.a?
Jayen

# 3 에 대한 한 가지 분명한 설명 window.a = 0;은 브라우저 환경에서만 작동하며 규칙에 의해서만 작동 한다는 것입니다 . 전역 객체를 이름 지정된 변수에 바인딩하는 window것은 ES 사양에 없으므로 V8 또는 Node.js와 같이 작동하지 않지만 this.a = 0;(전역 실행 컨텍스트에서 호출 된 경우) 사양 지정되어 있기 때문에 모든 환경에서 작동합니다. 가 있어야한다는 전역 객체. 에서 같은 인생에서 코드를 포장하는 경우 오프 주제 섹션, 당신은 통과 할 수 라는 이름의 매개 변수로 또는 전역 객체에 대한 직접 참조를 얻을 수 있습니다. thiswindowglobal
Sherlock_HJ

@Sherlock_HJ : "브라우저에 추가했습니다"; 그것은 대답의 앞 부분에 있지만 사람들이 그것을 건너 뛸 수 있도록 추가했습니다. 그것은 지금 사양에있다 ; 지나가는 동안에는 브라우저가없는 브라우저를 찾을 수 없습니다. 부록 B에 없는 것이 약간 놀랍습니다 .
TJ Crowder

@TJCrowder 따라서로 선언 된 전역 변수는 var a = 0;자동으로 전역 객체의 속성이됩니다. 내가 선언하면 var b = 0;함수 선언 내에서, 또한 몇 가지 기본 객체의 속성이 될 것인가?
ezpresso

@ezpresso : 아니요. 그것들은 객체의 속성 ( 그들이 나타나는 곳 의 ExecutionContextVariableEnvironmentEnvironmentRecordEnvironmentRecord ; 여기여기의 세부 사항 )이되지만, 프로그램 코드에서 그 객체에 직접 액세스 할 수있는 방법은 없습니다.
TJ Crowder

40

간단하게 유지 :

a = 0

위의 코드는 전역 범위 변수를 제공합니다

var a = 0;

이 코드는 현재 범위에서 사용되는 변수를 제공합니다.

window.a = 0;

이것은 일반적으로 전역 변수와 동일합니다.


귀하의 문 "위의 코드는 전역 범위 변수 제공""그 아래에이 코드는 현재 범위에서 사용되는 변수를 줄 것이다, 그리고" 함께는 첫 번째 라인과 액세스를 사용할 수없는 제안 a 에 따라 현재 범위. 할 수 있습니다. 또한 "전역 변수"를 사용하는 것은 약간의 문제입니다. "전역 변수"라고 말하는 두 곳은 말하지 않은 곳보다 더 전역 적이 지 않습니다.
TJ Crowder 2019

전역 자체는 현재 범위를 언급 한 장소를 포함하여 어디에서나 변수에 액세스 / 읽기 / 쓰기 할 수 있음을 의미합니다. 그리고 window.a와 'a'가 스크립트에서 전역 적이 지 않다고 제안하면 100 % 잘못되었습니다.
Umair Jabbar

3
@Umair : "글로벌 자체는 어디에서나 변수에 액세스 / 읽기 / 쓰기를 할 수 있음을 의미합니다 . " 다시 말하지만, 당신은 첫 번째를 부르는 것 같고 중간보다 더 "글로벌"한 것입니다. 물론 그렇지 않습니다.
TJ Crowder 2013

4
가운데 하나는 함수 내에서 사용되는 것으로 간주되며 기본 범위에서 사용하면 모두 동일합니다. 함수 내에서 내 가정을 VAR을 한 사용
UMAIR 자바

4
@Umair : "함수 안에 var를 사용하는 것이 제 전제였습니다" 아, 좋습니다. 그러나 그것은 질문이 아닙니다. 그 질문은 "전 세계적으로" 매우 명확하게 말한다 . 가정을 바꾸려면 (충분히 공평하고 더 일반적인 요점을 설명하기 위해), 대답에서하고있는 것이 분명해야합니다.
TJ Crowder

10
<title>Index.html</title>
<script>
    var varDeclaration = true;
    noVarDeclaration = true;
    window.hungOnWindow = true;
    document.hungOnDocument = true;
</script>
<script src="external.js"></script>

/* external.js */

console.info(varDeclaration == true); // could be .log, alert etc
// returns false in IE8

console.info(noVarDeclaration == true); // could be .log, alert etc
// returns false in IE8

console.info(window.hungOnWindow == true); // could be .log, alert etc
// returns true in IE8

console.info(document.hungOnDocument == true); // could be .log, alert etc
// returns ??? in IE8 (untested!)  *I personally find this more clugy than hanging off window obj

기본적으로 모든 변수가 중단되는 전역 객체가 있습니까? 예 : 'globals.noVar 선언'


아주 좋은 탐험. window.*선언 사용에 대한 명확한 안내서 . 이 선언은 코드를 복사하여 붙여 넣는 것에 대해 가장 안전하고 명확합니다.
Dan

7

TJ Crowder 의 탁월한 답변을 바탕으로 : ( 주제 : 혼란을 피하십시오window )

이것은 그의 아이디어의 예입니다.

HTML

<!DOCTYPE html>
<html>
  <head>
    <script type="text/javascript" src="init.js"></script>
    <script type="text/javascript">
      MYLIBRARY.init(["firstValue", 2, "thirdValue"]);
    </script>
    <script src="script.js"></script>
  </head>

  <body>
    <h1>Hello !</h1>
  </body>    
</html>

init.js ( 이 답변을 기반으로 함 )

var MYLIBRARY = MYLIBRARY || (function(){
    var _args = {}; // private

    return {
        init : function(Args) {
            _args = Args;
            // some other initialising
        },
        helloWorld : function(i) {
            return _args[i];
        }
    };
}());

script.js

// Here you can use the values defined in the html as if it were a global variable
var a = "Hello World " + MYLIBRARY.helloWorld(2);

alert(a);

다음은 plnkr 입니다. 그것이 도움이되기를 바랍니다!


5

전 세계적으로 의미 상 차이는 없습니다.

그러나 a=0값을 선언되지 않은 변수로 설정하므로 실제로 피해야 합니다.

또한 전역 범위를 전혀 편집하지 않으려면 클로저를 사용하십시오.

(function() {
   // do stuff locally

   // Hoist something to global scope
   window.someGlobal = someLocal
}());

항상 필요한 경우 클로저를 사용하고 항상 글로벌 범위로 호이스트하십시오. 어쨌든 대부분의 통신에 비동기 이벤트 처리를 사용해야합니다.

@AvianMoncellor가 언급했듯이 var a = foo파일 범위에 대한 전역을 선언 하는 IE 버그가 있습니다. 이것은 IE의 악명 높은 깨진 통역사와 관련된 문제입니다. 이 버그는 친숙하게 들리므로 아마도 사실 일 것입니다.

그러니까 window.globalName = someLocalpointer


2
"전 세계적으로 의미 상 차이는 없습니다." 그러나 실용적인 측면에서 그것은 단지 작은 귀결 - 사실, 엄청난 의미 차이가있다,이 속성을 정의 도착하는 메커니즘은 완전히 다른 실제 (에 당신이 할 수없는 그 차이 ). deletevar
TJ Crowder 2019

@TJ Crowder 나는 몰랐습니다. 변수 선언이 변수 객체의 속성을 설정한다고 생각했습니다. 그것들을 삭제할 수 없다는 것을 몰랐습니다.
Raynos

예. 또한를 사용하는 경우 이전에 정의되어 있습니다 var. 그것들은 실질적으로 동일한 실제 결과를 갖는 완전히 다른 메커니즘입니다. :-)
TJ Crowder

@TJ Crowder 나는 그것이 var범위의 멈춤으로 점프하는 것을 언급하는 것을 잊었다 .
Raynos
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.