“let”과“var”의 차이점은 무엇입니까?


4538

ECMAScript 6는 let진술을 소개 했습니다 .

"로컬"변수라고 설명되어 있지만 var키워드 와 어떻게 다르게 동작하는지 잘 모르겠습니다 .

차이점은 무엇입니까? 때해야 let이상 사용할 수 var?


104
ECMAScript는 표준이며 6 판 초안에let 포함되며 최종 사양에 포함될 가능성이 높습니다.
Richard Ayotte

5
ES6 기능의 최신 지원 매트릭스 (let 포함)는 kangax.github.io/es5-compat-table/es6 을 참조하십시오 . Firefox를 작성할 당시에는 Chrome과 IE11이 모두 지원합니다 (FF의 구현은 표준이 아니라고 생각하지만).
Nico Burns

22
가장 오랫동안 for 루프의 vars가 랩핑 된 함수의 범위에 속하는지 알지 못했습니다. 처음으로 이것을 알아 낸 것을 기억하고 매우 어리석은 것으로 생각했습니다. 다른 이유로 f을 어떻게 사용할 수 있는지, 어떤 경우에는 실제로 for 루프에서 var를 사용하고 블록 범위를 지정하지 않으려는 방법을 알고 있지만 힘이 있습니다.
Eric Bishard

1
이것은 매우 잘 읽습니다 wesbos.com/javascript-scoping
onmyway133

1
잘 설명 된 답변 here stackoverflow.com/a/43994458/5043867
Pardeep Jain

답변:


6096

범위 지정 규칙

주요 차이점은 범위 지정 규칙입니다. var키워드로 선언 된 변수는 직접 함수 본문 (따라서 함수 범위) let에 범위가 지정되는 반면 변수는 즉시 둘러싸 는 범위에 있습니다.{ } (따라서 블록 범위) 로 표시되는 블록에 .

function run() {
  var foo = "Foo";
  let bar = "Bar";

  console.log(foo, bar);

  {
    let baz = "Bazz";
    console.log(baz);
  }

  console.log(baz); // ReferenceError
}

run();

let키워드가 언어에 도입 된 이유 는 함수 범위이기 때문에 혼란스럽고 JavaScript의 주요 버그 소스 중 하나였습니다.

다른 stackoverflow 질문 에서이 예제를 살펴보십시오 .

var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
  // and store them in funcs
  funcs[i] = function() {
    // each should log its value.
    console.log("My value: " + i);
  };
}
for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

My value: 3funcs[j]();익명 함수가 동일한 변수에 바인드되어 호출 될 때마다 콘솔에 출력되었습니다 .

사람들은 루프에서 올바른 값을 캡처하기 위해 즉시 호출 된 함수를 만들어야했지만 머리카락도 많았습니다.

게양

var키워드로 선언 된 변수 는 호이 스팅 ( undefined코드가 실행되기 전에 초기화 됨 )되지만 선언되기 전에도 포함 범위에서 액세스 할 수 있습니다.

function run() {
  console.log(foo); // undefined
  var foo = "Foo";
  console.log(foo); // Foo
}

run();

let변수는 정의가 평가 될 때까지 초기화되지 않습니다. 초기화하기 전에 액세스하면 ReferenceError. 변수는 블록의 시작부터 초기화가 처리 될 때까지 "임시 데드 존"에 있다고합니다.

function checkHoisting() {
  console.log(foo); // ReferenceError
  let foo = "Foo";
  console.log(foo); // Foo
}

checkHoisting();

전역 객체 속성 생성

최상위 레벨 let에서는와 달리 var전역 객체에 대한 속성을 만들지 않습니다.

var foo = "Foo";  // globally scoped
let bar = "Bar"; // globally scoped

console.log(window.foo); // Foo
console.log(window.bar); // undefined

재 선언

엄격 모드에서는 SyntaxError를 발생 var시키면서 동일한 범위에서 동일한 변수를 다시 선언 할 수 있습니다 let.

'use strict';
var foo = "foo1";
var foo = "foo2"; // No problem, 'foo' is replaced.

let bar = "bar1";
let bar = "bar2"; // SyntaxError: Identifier 'bar' has already been declared

23
원할 때마다 블록을 만들 수 있습니다. function () {code; {let inBlock = 5; } 코드; };
평균 조

177
let 문의 목적은 특정 블록에서 필요하지 않은 경우에만 메모리를 확보하는 것입니까?
NoBugs

219
@NoBugs, 예. 변수는 필요한 곳에만 존재하는 것이 좋습니다.
배트맨

67
let블록 표현식 let (variable declaration) statement은 표준이 아니며 향후 bugzilla.mozilla.org/show_bug.cgi?id=1023609 에서 제거 될 예정 입니다.
Gajus

19
따라서 var를 사용하는 것이 어떤 경우인지 생각할 수 없습니다. 누군가 var를 사용하는 것이 바람직한 상황의 예를 들어 줄 수 있습니까?
Luis Sieira

621

let폐쇄와 관련된 문제를 피하기 위해 사용할 수도 있습니다. 아래 예제와 같이 오래된 참조를 유지하는 대신 새로운 가치를 결속시킵니다.

for(var i=1; i<6; i++) {
  $("#div" + i).click(function () { console.log(i); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Clicking on each number will log to console:</p> 
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>

위 코드는 전형적인 JavaScript 클로저 문제를 보여줍니다. i변수 에 대한 참조 는의 실제 값이 아닌 클릭 핸들러 클로저에 저장됩니다 i.

모든 단일 클릭 핸들러는 6을 보유하는 카운터 오브젝트가 하나만 있으므로 각 클릭마다 6 개를 가져 오기 때문에 동일한 오브젝트를 참조합니다.

일반적인 해결 방법은 이것을 익명 함수로 감싸서 i인수로 전달 하는 것입니다. 이러한 문제는 다음을 사용하여 피할 수도 있습니다.letvar아래 코드와 같이 대신 .

(Chrome 및 Firefox 50에서 테스트)

for(let i=1; i<6; i++) {
  $("#div" + i).click(function () { console.log(i); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Clicking on each number will log to console:</p> 
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>


54
실제로 멋지다. 루프 바디에 괄호 안에 포함 된 "i"를 정의하고 "i"주위에 "클로저"를 형성하지 않기를 기대합니다. 물론 예는 그렇지 않습니다. 구문 관점에서 약간 혼란 스럽다고 생각하지만이 시나리오는 너무 일반적이므로 그런 식으로 지원하는 것이 좋습니다. 이 문제를 제기 해 주셔서 감사합니다.
Karol Kolenda

9
IE 11은을 지원 let하지만 모든 버튼에 대해 "6"을 경고합니다. 어떻게 let행동 해야하는지 말하는 소스 가 있습니까?
Jim Hunziker

10
귀하의 답변이 올바른 행동 인 것 같습니다 : developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Jim Hunziker

11
실제로 이것은 자바 스크립트의 일반적인 함정이며 이제는 let실제로 유용한 이유를 알 수 있습니다. 루프에서 이벤트 리스너를 설정하면 더 이상 i각 반복에서 로컬 범위 를 지정하기 위해 즉시 호출 된 함수 표현식이 필요하지 않습니다 .
Adrian Moisa

19
"let"을 사용하면이 문제가 지연됩니다. 따라서 각 반복은 개인 독립 블록 범위를 작성하지만 블록 내의 후속 변경으로 "i"변수가 여전히 손상 될 수 있습니다 (반복자 변수가 일반적으로 블록 내에서 변경 되지는 않지만 블록 내에서 선언 된 다른 let 변수는 허용 될 수 있음) 그들은 때문에 일) 및 기능 블록 캔 내에 선언, 호출시의 손상 값은 "I"는 다른 기능 블록 내에서 선언 "I"로 주를 따라서 같은 사적인 블럭 범위 동일한 참조.
gary

198

차이 무엇 letvar?

  • var명령문을 사용하여 정의 된 변수 는 함수 시작부터 정의 된 함수 전체 알려져 있습니다 .(*)
  • let명령문을 사용하여 정의 된 변수 는 정의 된 순간부터 정의 된 블록 에서만 알 수 있습니다 . (**)

차이점을 이해하려면 다음 코드를 고려하십시오.

// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here

function loop(arr) {
    // i IS known here, but undefined
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( var i = 0; i < arr.length; i++ ) {
        // i IS known here, and has a value
        // j IS NOT known here
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( let j = 0; j < arr.length; j++ ) {
        // i IS known here, and has a value
        // j IS known here, and has a value
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here
}

loop([1,2,3,4]);

for( var k = 0; k < arr.length; k++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS NOT known here
};

for( let l = 0; l < arr.length; l++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS known here, and has a value
};

loop([1,2,3,4]);

// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here

여기에서 변수 j는 첫 번째 for 루프에서만 알려져 있지만 이전과 이후에는 알려지지 않았습니다. 그러나 우리의 변수i 는 전체 기능에 알려져 있습니다.

또한 블록 범위 변수는 게양되지 않았기 때문에 선언되기 전에 알 수 없습니다. 또한 동일한 블록 내에서 동일한 블록 범위 변수를 다시 선언 할 수 없습니다. 이렇게하면 블록 범위 변수가 전역 또는 기능 범위 변수보다 오류가 덜 발생합니다.이 변수는 게양되어 여러 선언의 경우 오류가 발생하지 않습니다.


let오늘 사용하는 것이 안전 합니까?

어떤 사람들은 미래에 let 문만 사용할 것이며 var 문은 더 이상 사용되지 않을 것이라고 주장합니다. JavaScript 전문가 인 Kyle Simpson이것이 사실이 아니라고 믿는 이유에 대해 매우 정교한 기사를 썼습니다 .

그러나 오늘날에는 그렇지 않습니다. 실제로, 우리는 실제로 사용하기에 안전한지 스스로에게 물어볼 필요가 있습니다.let 진술 . 해당 질문에 대한 답변은 환경에 따라 다릅니다.

  • 서버 측 JavaScript 코드 ( Node.js )를 작성하는 경우 안전하게 사용할 수 있습니다.let 작성 명령문을 .

  • 클라이언트 측 JavaScript 코드를 작성하고 Traceur 또는 babel-standalone 과 같은 브라우저 기반 변환기를 사용하는 경우 안전하게 사용할 수 있습니다.let 명령문을 있지만 코드는 성능 측면에서 최적 일 수 있습니다.

  • 클라이언트 측 JavaScript 코드를 작성하고 traceur 쉘 스크립트 또는 Babel 과 같은 노드 기반 변환기를 사용하는 경우 안전하게 사용할 수 있습니다.let 명령문을 . 브라우저는 변환 된 코드에 대해서만 알기 때문에 성능 단점이 제한되어야합니다.

  • 클라이언트 측 JavaScript 코드를 작성 중이고 트랜스 파일러를 사용하지 않는 경우 브라우저 지원을 고려해야합니다.

    전혀 지원하지 않는 브라우저가 여전히 있습니다 let:

여기에 이미지 설명을 입력하십시오


브라우저 지원을 추적하는 방법

let이 답변을 읽을 당시의 진술을 지원하는 브라우저에 대한 최신 개요는 Can I Use페이지를 참조 하십시오 .


(*) JavaScript 변수가 들어 있기 때문에 전역 및 기능적으로 범위가 지정된 변수를 선언하기 전에 초기화하고 사용할 수 있습니다 .이것은 선언이 항상 범위의 맨 위에 있다는 것을 의미합니다.

(**) 블록 범위 변수는 게양되지 않습니다


14
답변 v4에 관해서 : i함수 블록의 모든 곳에서 알려져 있습니다! undefined값을 할당 할 때까지 (상승으로 인해) 시작 합니다! ps : let도 포함되어 있습니다 (블록을 ​​포함하는 맨 위에 있음). 그러나 ReferenceError처음 할당하기 전에 블록에서 참조 될 때 시간 을 줄 것 입니다. (ps2 : 나는 프로 세미콜론 같은 사람이지만 실제로 블록 뒤에 세미콜론이 필요하지 않습니다). 지원에 관한 현실 점검을 추가해 주셔서 감사합니다!
GitaarLAB

@GitaarLAB : Mozilla Developer Network 에 따르면 : "ECMAScript 2015에서 바인딩은 변수 호이 스팅에 종속되지 않습니다. 즉, 선언이 현재 실행 컨텍스트의 맨 위로 이동하지 않습니다." -어쨌든, 나는 내 대답을 약간 개선하여 let와 사이의 호이 스팅 행동의 차이점을 분명히해야합니다 var!
John Slegers

1
당신의 대답은 많이 향상되었습니다 (나는 철저히 확인했습니다). 귀하의 의견에서 언급 한 동일한 링크는 또한 "(let) 변수는 블록시작부터 초기화가 처리 될 때까지 "임시 데드 존 "에 있습니다 ." 즉, '식별자'( 'something'을 가리키는 텍스트 문자열 'reserved') 는 이미 관련 범위에 예약되어 있으며 그렇지 않으면 루트 / 호스트 / 창 범위의 일부가됩니다. 개인적으로 '게양'은 선언 된 '식별자'를 관련 범위로 예약 / 연결하는 것 이상을 의미합니다. 그들의 초기화 / 할당 / 수정 성을 배제하십시오!
GitaarLAB

그리고 .. +1. 당신이 연결 한 Kyle Simpson 기사는 훌륭한 글입니다. 감사합니다! 또한 "임시 데드 존", 즉 "TDZ"에 대해서도 명확합니다. 한 가지 흥미로운 것은 내가 추가하고 싶습니다 : 나는 MDN에 읽은 것을 let하고 const있었다 당신이 실제로 자신의 추가 기능이 필요한 경우에만 사용하는 것이 좋습니다 , '더 많은 작업의 결과 (쓰기 전용 const를 같은) 이러한 추가 기능 / 강제 점검 때문에 (현재) 엔진에 대해 '(및 범위 트리의 추가 범위 노드)를 적용 / 확인 / 확인 / 설정합니다.
GitaarLAB

1
MDN은 IE DOES가 let을 올바르게 해석한다고 말합니다. 무엇 이니? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Katinka Hesselink

146

다음 은 몇 가지 예와 함께 키워드에 대한 설명입니다let .

let매우 유사하게 작동합니다 var. 가장 큰 차이점은 var변수 의 범위 가 전체 둘러싸는 함수라는 것입니다

Wikipedia 의이 표 는 Javascript 1.7을 지원하는 브라우저를 보여줍니다.

Mozilla 및 Chrome 브라우저 만 지원합니다. IE, Safari 및 잠재적으로 다른 사람들은 그렇지 않습니다.


5
링크 된 문서의 핵심 텍스트는 "var과 매우 유사하게 작동합니다. 주요 차이점은 var 변수의 범위가 전체 둘러싸 기 함수"라는 것입니다.
Michael Burr

50
IE가 지원하지 않는다고 말하는 것은 기술적으로 정확하지만 그것이 모질라 전용 확장이라고 말하는 것이 더 정확합니다.
olliej 2009

55
@olliej, 실제로 Mozilla는 게임보다 앞서 있습니다. ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
Tyler Crompton

@TylerCrompton 그것은 몇 년 동안 예약 된 단어들입니다. mozilla가 추가되었을 때 관련 사양이없는 순전히 mozilla 확장이었습니다. ES6은 let 문의 동작을 정의해야하지만, mozilla가 구문을 도입 한 이후에 발생했습니다. moz에는 E4X도 있다는 점을 기억하십시오. E4X는 완전히 죽었고 moz 일뿐입니다.
olliej


112

수락 된 답변에 요점이 없습니다.

{
  let a = 123;
};

console.log(a); // ReferenceError: a is not defined

19
수락 된 답변은이 점을 예제에서 설명하지 않습니다. 허용 된 답변은 for루프 이니셜 라이저 에서만 입증되었으며 의 적용 범위가 크게 좁아 let졌습니다. 공감.
존 데이비스

37
@ stimpy77 "가장 가까운 둘러싸는 블록으로 범위가 지정됩니다"라고 명시 적으로 나타냅니다. 모든 매니페스트가 포함되어야합니까?
Dave Newton

6
예가 많았고 그 중 어느 것도 문제를 제대로 보여주지 못했습니다.
Jon Davis

5
이 기여는 "블록"이 단순히 괄호로 묶인 줄 집합 일 수 있음을 보여줍니다. 즉, 어떤 종류의 제어 흐름, 루프 등과도 연관 될 필요가 없습니다.
webelo

81

let

블록 범위

let키워드를 사용하여 선언 된 변수 는 블록 범위이므로 선언 된 블록 에서만 사용할 수 있습니다 .

최상위 수준 (함수 외부)

최상위 수준에서를 사용하여 선언 된 변수는 let전역 객체에 대한 속성을 만들지 않습니다.

var globalVariable = 42;
let blockScopedVariable = 43;

console.log(globalVariable); // 42
console.log(blockScopedVariable); // 43

console.log(this.globalVariable); // 42
console.log(this.blockScopedVariable); // undefined

함수 내부

함수 내부 (하지만 블록 외부)의 let범위는와 같습니다 var.

(() => {
  var functionScopedVariable = 42;
  let blockScopedVariable = 43;

  console.log(functionScopedVariable); // 42
  console.log(blockScopedVariable); // 43
})();

console.log(functionScopedVariable); // ReferenceError: functionScopedVariable is not defined
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined

블록 내부

let블록 내부를 사용하여 선언 된 변수는 해당 블록 외부에서 액세스 할 수 없습니다.

{
  var globalVariable = 42;
  let blockScopedVariable = 43;
  console.log(globalVariable); // 42
  console.log(blockScopedVariable); // 43
}

console.log(globalVariable); // 42
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined

루프 내부

letin 루프로 선언 된 변수는 해당 루프 내에서만 참조 할 수 있습니다.

for (var i = 0; i < 3; i++) {
  var j = i * 2;
}
console.log(i); // 3
console.log(j); // 4

for (let k = 0; k < 3; k++) {
  let l = k * 2;
}
console.log(typeof k); // undefined
console.log(typeof l); // undefined
// Trying to do console.log(k) or console.log(l) here would throw a ReferenceError.

클로저가있는 루프

루프 let대신에 사용하면 var각 반복마다 새로운 변수가 생깁니다. 즉, 루프 내부에서 클로저를 안전하게 사용할 수 있습니다.

// Logs 3 thrice, not what we meant.
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}

// Logs 0, 1 and 2, as expected.
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log(j), 0);
}

일시적 데드 존

일시적인 데드 존 (dead zone)으로 인해 선언 된 변수는 선언 let되기 전에 액세스 할 수 없습니다. 그렇게하려고하면 오류가 발생합니다.

console.log(noTDZ); // undefined
var noTDZ = 43;
console.log(hasTDZ); // ReferenceError: hasTDZ is not defined
let hasTDZ = 42;

다시 선언하지 않음

을 사용하여 동일한 변수를 여러 번 선언 할 수 없습니다 let. let또한를 사용하여 선언 된 다른 변수와 동일한 식별자를 사용하여 변수를 선언 할 수 없습니다 var.

var a;
var a; // Works fine.

let b;
let b; // SyntaxError: Identifier 'b' has already been declared

var c;
let c; // SyntaxError: Identifier 'c' has already been declared

const

const 꽤 비슷합니다 let - 그것은의 블록 범위와있다 TDZ. 그러나 다른 두 가지가 있습니다.

재 할당 없음

를 사용하여 선언 된 변수는 const재 할당 할 수 없습니다.

const a = 42;
a = 43; // TypeError: Assignment to constant variable.

값이 변경 불가능하다는 의미는 아닙니다. 여전히 속성을 변경할 수 있습니다.

const obj = {};
obj.a = 42;
console.log(obj.a); // 42

불변의 객체를 가지려면을 사용해야합니다 Object.freeze().

이니셜 라이저가 필요합니다

를 사용하여 변수를 선언 할 때는 항상 값을 지정해야합니다 const.

const a; // SyntaxError: Missing initializer in const declaration

51

다음은이 둘의 차이점에 대한 예입니다 (Chrome에 대한 지원 시작).
여기에 이미지 설명을 입력하십시오

보시다시피 var j변수는 여전히 for 루프 범위 (블록 범위) let i외부에 값이 있지만 변수는 for 루프 범위 외부에서 정의되지 않습니다.

"use strict";
console.log("var:");
for (var j = 0; j < 2; j++) {
  console.log(j);
}

console.log(j);

console.log("let:");
for (let i = 0; i < 2; i++) {
  console.log(i);
}

console.log(i);


2
여기서 어떤 도구를보고 있습니까?
Barton

20
크롬 devtools
vlio20

시나몬의 데스크탑 애플릿 개발자로서, 나는 그런 빛나는 도구에 노출되지 않았습니다.
Barton

48

약간의 차이점이 있습니다. let범위 지정은 다른 언어에서 변수 범위 지정과 비슷하게 동작합니다.

예를 들어, 그것은 블록을 둘러싸고, 선언되기 전에 존재하지 않습니다.

그러나 let최신 자바 스크립트 구현의 일부일 뿐이며 다양한 수준의 브라우저 지원 기능 이 있다는 점 은 주목할 가치가 있습니다.


11
ECMAScript가 표준이며 6 판 초안에let 포함 되어 있으며 최종 사양에 포함될 가능성이 높습니다.
Richard Ayotte

23
그것이 3 년의 차이입니다 : D
olliej

4
이 질문에 답한 것은 2012 년에도 여전히 Mozilla 브라우저 만 지원하는 경우입니다 let. Safari, IE 및 Chome은 모두 그렇지 않습니다.
유사 절약

2
실수로 실수로 부분 블록 범위를 생성한다는 아이디어는 블록 상단에 정의 된 let변수를 사용하는 것이 좋습니다 let. if단지 몇 줄의 코드 이상의 문장이 있다면 , 변수가 정의 될 때까지 해당 변수를 사용할 수 없다는 것을 잊을 수 있습니다. 좋은 점 !!!
Eric Bishard

2
@EricB : yes and no : "ECMAScript 2015에서는 변수를 블록의 상단으로 let 끌어 올립니다 . 그러나 변수 선언 전에 블록에서 변수를 참조 하면 ReferenceError가 발생합니다 (나의 참고 : good old 대신 undefined). 변수는 블록의 시작부터 선언이 처리 될 때까지 '임시 데드 존'에 있습니다. " "기본 블록이 하나뿐이므로 스위치 문"도 마찬가지입니다. 출처 : developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
GitaarLAB 2016 년

26

주요 차이점은입니다 범위 반면, 차이 하자가 내부에서만 사용할 수 있습니다 범위 , 루프처럼이 선언있어 VAR는 예를 들어 루프 외부에서 액세스 할 수 있습니다. MDN 설명서 (예 : MDN) :

하자가 당신이 사용되는 블록, 문, 또는 표현 범위가 제한되는 변수를 선언 할 수 있습니다. 이것은 블록 범위와 상관없이 변수를 전체적으로 또는 전체적으로 로컬로 정의하는 var 키워드 와 다릅니다 .

let에 의해 선언 된 변수는 포함 된 하위 블록뿐만 아니라 자신이 정의 된 블록을 해당 범위로 갖습니다. 이러한 방법으로 매우 같은 작품 VAR을 . 가장 큰 차이점은 var 변수 의 범위 가 전체 둘러싸는 함수라는 것입니다.

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // same variable!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // different variable
    console.log(x);  // 2
  }
  console.log(x);  // 1
}`

프로그램 및 기능의 최상위 레벨에서 보자 는 달리, VAR , 전역 객체의 속성을 만들지 않습니다. 예를 들면 다음과 같습니다.

var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined

블록 내에서 사용될 때 변수의 범위를 해당 블록으로 제한하십시오. 범위가 선언 된 함수 내에 범위가있는 var 의 차이점에 유의하십시오 .

var a = 1;
var b = 2;

if (a === 1) {
  var a = 11; // the scope is global
  let b = 22; // the scope is inside the if-block

  console.log(a);  // 11
  console.log(b);  // 22
} 

console.log(a); // 11
console.log(b); // 2

또한 ECMA6 기능을 잊지 마십시오. 아직 완벽하게 지원되지는 않으므로 babel 웹 사이트 방문에 대한 자세한 내용은 Babel 등을 사용하여 ECMA5로 항상 변환하는 것이 좋습니다.


24
  • 게양하지 않는 변수

    let것이다 하지 호이스트 가 나타나지 블록의 전체 범위이다. 이와 대조적으로, var아래로 끌어 올릴 수있다.

    {
       console.log(cc); // undefined. Caused by hoisting
       var cc = 23;
    }
    
    {
       console.log(bb); // ReferenceError: bb is not defined
       let bb = 23;
    }

    사실, 당 @Bergi는 모두 varlet게양된다 .

  • 가비지 콜렉션

    블록 범위는 let메모리를 회수하기위한 클로저 및 가비지 수집과 관련이 있습니다. 치다,

    function process(data) {
        //...
    }
    
    var hugeData = { .. };
    
    process(hugeData);
    
    var btn = document.getElementById("mybutton");
    btn.addEventListener( "click", function click(evt){
        //....
    });

    click핸들러 콜백은 필요로하지 않는다 hugeData전혀 변수를. 이론적으로 process(..)실행 후에 는 거대한 데이터 구조 hugeData가 가비지 수집 될 수 있습니다. 그러나 click함수가 전체 범위에 걸쳐 폐쇄되어 있기 때문에 일부 JS 엔진은 여전히이 거대한 구조를 유지해야 할 수도 있습니다.

    그러나 블록 범위는이 거대한 데이터 구조를 가비지 수집으로 만들 수 있습니다.

    function process(data) {
        //...
    }
    
    { // anything declared inside this block can be garbage collected
        let hugeData = { .. };
        process(hugeData);
    }
    
    var btn = document.getElementById("mybutton");
    btn.addEventListener( "click", function click(evt){
        //....
    });
  • let 루프

    let루프에서 루프를 반복 때마다 루프를 다시 바인딩 할 수 있으므로 이전 루프 반복의 끝에서 값을 다시 할당해야합니다. 치다,

    // print '5' 5 times
    for (var i = 0; i < 5; ++i) {
        setTimeout(function () {
            console.log(i);
        }, 1000);  
    }

    그러나 교체 var와 함께let

    // print 1, 2, 3, 4, 5. now
    for (let i = 0; i < 5; ++i) {
        setTimeout(function () {
            console.log(i);
        }, 1000);  
    }

    때문에 let)) 각각의 반복을 initialiser 표현 B를 A의 그 이름을 가진 새로운 어휘 환경을 조성 (와 previosly 증가 표현)을 평가하는 자세한 내용은 여기 .


4
그들이 게양하는 YIP하지만 때문에 (드럼 롤) 임시 사각 지대의 게양하지 것처럼 행동 -이 :-) 선언 될 때까지 식별자가 접근 할 수 없었던 매우 극적인 이름
Drenai

따라서 게양되었지만 사용할 수 없습니까? 그것이 '게양되지 않은 것'과 다른 점은 무엇입니까?
N-ate

희망적으로 Brian 또는 Bergi가이 질문에 답하기 위해 다시 왔습니다. let의 선언이 호이스트되지만 과제가 아닙니까? 감사!
N-ate

1
@ N-ate, Bergi의 한 게시물 이 있습니다. 아마도 답을 찾을 수 있습니다.
zangw

흥미롭게도 호이 스팅이라고도합니다. 기술적으로 파싱 엔진이 미리 캡처하고 있지만 모든 의도와 목적을 위해 프로그래머는 존재하지 않는 것처럼 처리해야합니다. 반면에 var의 게양은 프로그래머에게 영향을 미칩니다.
N-ate

19

다음은 다른 사람들이 이미 작성한 내용을 추가하는 예입니다. 함수의 배열을 만들고 싶다고 가정합니다 adderFunctions. 여기서 각 함수는 단일 숫자 인수를 가져 와서 인수와 함수의 인덱스의 합계를 배열로 반환합니다. 키워드를 adderFunctions사용하여 루프 로 생성하려고 var하면 누군가가 순진하게 기대하는 방식으로 작동하지 않습니다.

// An array of adder functions.
var adderFunctions = [];

for (var i = 0; i < 1000; i++) {
  // We want the function at index i to add the index to its argument.
  adderFunctions[i] = function(x) {
    // What is i bound to here?
    return x + i;
  };
}

var add12 = adderFunctions[12];

// Uh oh. The function is bound to i in the outer scope, which is currently 1000.
console.log(add12(8) === 20); // => false
console.log(add12(8) === 1008); // => true
console.log(i); // => 1000

// It gets worse.
i = -8;
console.log(add12(8) === 0); // => true

위의 프로세스는 i범위 for가 각 함수가 작성된 블록 의 반복을 넘어 확장 되기 때문에 원하는 함수 배열을 생성하지 않습니다 . 대신 루프의 끝 i에서 각 함수의 닫힘은 i의 모든 익명 함수에 대한 루프 끝의 값 (1000)을 나타 adderFunctions냅니다. 이것은 우리가 원하는 것이 아닙니다. 이제 우리는 정확히 같은 동작을 가진 1000 개의 서로 다른 함수 배열을 메모리에 갖습니다. 그리고 이후에의 값을 업데이트 i하면 돌연변이가 모든에 영향을 미칩니다 adderFunctions.

그러나 let키워드를 사용하여 다시 시도 할 수 있습니다 .

// Let's try this again.
// NOTE: We're using another ES6 keyword, const, for values that won't
// be reassigned. const and let have similar scoping behavior.
const adderFunctions = [];

for (let i = 0; i < 1000; i++) {
  // NOTE: We're using the newer arrow function syntax this time, but 
  // using the "function(x) { ..." syntax from the previous example 
  // here would not change the behavior shown.
  adderFunctions[i] = x => x + i;
}

const add12 = adderFunctions[12];

// Yay! The behavior is as expected. 
console.log(add12(8) === 20); // => true

// i's scope doesn't extend outside the for loop.
console.log(i); // => ReferenceError: i is not defined

이번에 ifor루프가 반복 될 때마다 리바운드됩니다 . 각 함수는 이제 i함수 생성 시점의 값을 유지하고 adderFunctions예상대로 작동합니다.

이제 두 가지 동작을 이미지 믹싱 하면 동일한 스크립트에서 최신 letconst이전 을 혼합하지 않는 것이 좋습니다 var. 그렇게하면 결과적으로 혼란스러운 코드가 생길 수 있습니다.

const doubleAdderFunctions = [];

for (var i = 0; i < 1000; i++) {
    const j = i;
    doubleAdderFunctions[i] = x => x + i + j;
}

const add18 = doubleAdderFunctions[9];
const add24 = doubleAdderFunctions[12];

// It's not fun debugging situations like this, especially when the
// code is more complex than in this example.
console.log(add18(24) === 42); // => false
console.log(add24(18) === 42); // => false
console.log(add18(24) === add24(18)); // => false
console.log(add18(24) === 2018); // => false
console.log(add24(18) === 2018); // => false
console.log(add18(24) === 1033); // => true
console.log(add24(18) === 1030); // => true

이런 일이 일어나지 않도록하십시오. 린터를 사용하십시오.

참고 : 이것은 루프 에서 var/ let동작과 이해하기 쉬운 함수 클로저 를 보여주기위한 교육 예제입니다 . 이것은 숫자를 추가하는 끔찍한 방법입니다. 그러나 익명 함수 클로저에서 데이터를 캡처하는 일반적인 기술은 실제 상황에서는 다른 상황에서 발생할 수 있습니다. YMMV.


2
@aborz : 두 번째 예제에서도 매우 멋진 익명 함수 구문입니다. C #에서 익숙한 것입니다. 나는 오늘 무언가를 배웠다.
Barton

수정 : 기술적으로 여기에 설명 된 화살표 함수 구문 => developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Barton

3
실제로는 필요하지 않습니다 let value = i;. 이 for문장은 어휘 블록을 만듭니다.
칫솔

17

차이점은 각각 선언 된 변수 의 범위 에 있습니다.

실제로 범위 차이로 인해 여러 가지 유용한 결과가 있습니다.

  1. let변수는 가장 가까운 둘러싸는 블록 ( { ... }) 에만 표시됩니다 .
  2. let변수는 변수가 선언 된 후에 발생하는 코드 줄에서만 사용할 수 있습니다 ( 호이 스팅 되더라도) !).
  3. let변수는 이후 var또는 로 다시 선언 할 수 없습니다 let.
  4. 전역 let변수는 전역 window개체에 추가되지 않습니다 .
  5. let변수는 클로저와 함께 사용하기 쉽습니다 ( 경쟁 조건을 유발하지 않음 ).

let변수의 가시성을 줄이고 예상치 못한 이름 충돌이 조기에 발견 될 가능성을 높이면 제한 사항이 적용됩니다 . 이를 통해 도달 가능성을 포함하여 변수를 추적하고 추론하기가 더 쉬워집니다 (미사용 메모리를 되 찾는 데 도움이 됨).

따라서, let 변수는 큰 프로그램에서 사용되거나 독립적으로 개발 된 프레임 워크가 새롭고 예기치 않은 방식으로 결합 될 때 문제를 일으킬 가능성이 줄어 듭니다.

var루프 (# 5)에서 클로저를 사용할 때 또는 코드에서 외부에서 볼 수있는 전역 변수를 선언 할 때 단일 바인딩 효과를 원하는 경우에도 여전히 유용 할 수 있습니다 (# 4). 트랜스 파일러 공간에서 핵심 언어로 마이그레이션하는 var경우 내보내기 용도 로 대체 될 수 export있습니다.

1. 가장 가까운 엔 클로징 블록 외부에서 사용하지 마십시오. 이 코드 x블록은 다음으로 선언 된 블록 외부 에서 두 번째 사용이 발생 하기 때문에 참조 오류를 발생시킵니다 let.

{
    let x = 1;
}
console.log(`x is ${x}`);  // ReferenceError during parsing: "x is not defined".

대조적으로, 동일한 예제가 var작동합니다.

2. 선언 전 사용 안함 :
이 코드 블록은 코드 가 선언되기 전에 사용되기 ReferenceError때문에 코드를 실행할 수 있기 x전에 다음을 처리합니다.

{
    x = x + 1;  // ReferenceError during parsing: "x is not defined".
    let x;
    console.log(`x is ${x}`);  // Never runs.
}

대조적으로, var예외가 발생하지 않고 구문 분석 및 실행 되는 동일한 예제 .

3. 재 선언 없음 : 다음 코드는 선언 된 변수가 let나중에 재 선언되지 않을 수 있음을 보여줍니다 .

let x = 1;
let x = 2;  // SyntaxError: Identifier 'x' has already been declared

4. 다음에 첨부되지 않은 글로벌 window:

var button = "I cause accidents because my name is too common.";
let link = "Though my name is common, I am harder to access from other JS files.";
console.log(link);  // OK
console.log(window.link);  // undefined (GOOD!)
console.log(window.button);  // OK

5. 클로저로 쉽게 사용 :로 선언 된 변수는 var루프 내부 클로저에서 제대로 작동하지 않습니다. 다음은 변수 i가 다른 시점에 가지고 있는 일련의 값을 출력하는 간단한 루프입니다 .

for (let i = 0; i < 5; i++) {
    console.log(`i is ${i}`), 125/*ms*/);
}

구체적으로 다음과 같이 출력됩니다.

i is 0
i is 1
i is 2
i is 3
i is 4

JavaScript에서는 종종 변수가 생성 될 때보 다 훨씬 나중에 변수를 사용합니다. 클로저가 전달 된 상태에서 출력을 지연 시켜서 이것을 증명할 때 setTimeout:

for (let i = 0; i < 5; i++) {
    setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}

... 우리가 고수하는 한 출력은 변경되지 않습니다 let. 반대로 우리가 var i대신 사용했다면 :

for (var i = 0; i < 5; i++) {
    setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}

... 루프가 예기치 않게 "i is 5"를 다섯 번 출력합니다.

i is 5
i is 5
i is 5
i is 5
i is 5

5
# 5는 경쟁 조건으로 인한 것이 아닙니다. var대신에 let코드 를 사용 하면 코드가 다음과 같습니다. var i = 0; while (i < 5) { doSomethingLater(); i++; } i은 폐쇄 외부에 있으며 doSomethingLater()실행 i시간에 따라 이미 5 배씩 증가하므로 출력은 i is 55 배입니다. 를 사용 let하면 변수 i가 클로저 내에 있으므로 각 비동기 호출은로 i작성된 '전역' 호출 대신 자체 사본을 가져 옵니다 var.
Daniel T.

@DanielT. : 루프 초기화 프로그램에서 변수 정의를 들어 올리는 변환에 대해서는 아무것도 설명하지 않는다고 생각합니다. 그것은의 의미에 대한 일반적인 정의입니다 for. 좀 더 정확한 변환은 더 복잡하지만 고전적인 for (var i = 0; i < 5; i++) { (function(j) { setTimeout(_ => console.log(i is $ {j} ), 125/*ms*/); })(i); }는 "function-activation record"를 도입하여 각 값을 함수 내부의 i이름으로 저장 j합니다.
mormegil

14

다음 두 함수가 차이점을 보여주기를 바랍니다.

function varTest() {
    var x = 31;
    if (true) {
        var x = 71;  // Same variable!
        console.log(x);  // 71
    }
    console.log(x);  // 71
}

function letTest() {
    let x = 31;
    if (true) {
        let x = 71;  // Different variable
        console.log(x);  // 71
    }
    console.log(x);  // 31
}

13

let 우리가 다음과 같이 할 수 있기 때문에 흥미 롭습니다.

(() => {
    var count = 0;

    for (let i = 0; i < 2; ++i) {
        for (let i = 0; i < 2; ++i) {
            for (let i = 0; i < 2; ++i) {
                console.log(count++);
            }
        }
    }
})();

계산 결과는 [0, 7]입니다.

이므로

(() => {
    var count = 0;

    for (var i = 0; i < 2; ++i) {
        for (var i = 0; i < 2; ++i) {
            for (var i = 0; i < 2; ++i) {
                console.log(count++);
            }
        }
    }
})();

[0, 1] 만 계산합니다.


2
이것은 내가 누군가가 가변 그림자처럼 행동하는 것을 처음 본 것입니다. 아니요, let의 목적은 섀도 잉을 활성화하지 않는 것입니다
John Haugeland

1
목적? 그것은 구조입니다, 당신은 그것을 사용할 수 있습니다 그러나 당신이 원하는대로, 흥미로운 방법 중 하나는 이와 같습니다.
Dmitry

13

기능 VS 블록 범위 :

주요 차이점 varlet그 변수 선언이다 var되는 기능 범위 . 로 선언 된 함수 let블록 범위 입니다. 예를 들면 다음과 같습니다.

function testVar () {
  if(true) {
    var foo = 'foo';
  }

  console.log(foo);
}

testVar();  
// logs 'foo'


function testLet () {
  if(true) {
    let bar = 'bar';
  }

  console.log(bar);
}

testLet(); 
// reference error
// bar is scoped to the block of the if statement 

변수 var:

첫 번째 함수 testVar가 호출 될 때으로 선언 된 변수 foo varif명령문 외부에서 여전히 액세스 할 수 있습니다 . 이 변수 foo함수 범위 내 어디에서나 사용할 수 있습니다 .testVar

변수 let:

두 번째 함수 testLet가 변수 막대로 호출되면으로 선언되어 명령문 let내에서만 액세스 할 수 있습니다 if. 변수로 선언되기 때문에 let되는 블록 범위 (블록 중괄호의 코드는 여기서 예를 들어 if{}, for{}, function{}).

let 변수는 게양되지 않습니다 :

또 다른 차이점 varlet선언과 변수입니다 let 게양되지 않습니다 . 이 동작을 설명하는 가장 좋은 방법은 예입니다.

를 가진 변수는 게양 let 되지 않습니다 :

console.log(letVar);

let letVar = 10;
// referenceError, the variable doesn't get hoisted

와 변수 var DO GET 게양 :

console.log(varVar);

var varVar = 10;
// logs undefined, the variable gets hoisted

Global let은 다음에 연결되지 않습니다 window.

let전역 범위에서 선언 된 변수 (함수가 아닌 코드)는 전역 window개체 의 속성으로 추가되지 않습니다 . 예를 들어 (이 코드는 전역 범위에 있습니다) :

var bar = 5;
let foo  = 10;

console.log(bar); // logs 5
console.log(foo); // logs 10

console.log(window.bar);  
// logs 5, variable added to window object

console.log(window.foo);
// logs undefined, variable not added to window object


때해야 let이상 사용할 수 var?

사용 let을 통해 var당신은 단순히 더 구체적인를 범위가 수 있기 때문에 때마다. 이는 많은 변수를 처리 할 때 발생할 수있는 잠재적 인 이름 충돌을 줄입니다. var전역 변수를 명시 적으로 window객체 에 배치하려고 할 때 사용할 수 있습니다 (실제로 필요한 경우 항상 신중하게 고려하십시오).


9

또한 적어도 Visual Studio 2015, TypeScript 1.5에서 "var"은 블록에 동일한 변수 이름을 여러 번 선언 할 수 있지만 "let"은 그렇지 않습니다.

컴파일 오류가 발생하지 않습니다.

var x = 1;
var x = 2;

이것은 :

let x = 1;
let x = 2;

9

var 전역 범위 (호이스트 가능) 변수입니다.

let그리고 const블록 범위입니다.

test.js

{
    let l = 'let';
    const c = 'const';
    var v = 'var';
    v2 = 'var 2';
}

console.log(v, this.v);
console.log(v2, this.v2);
console.log(l); // ReferenceError: l is not defined
console.log(c); // ReferenceError: c is not defined


8

사용할 때 let

let키워드는 어떤 블록 (일반적으로의 범위에 변수 선언 부착 { .. }이에 포함 된 것 쌍). 즉, let암시 적으로 그 변수 선언에 대한 모든 블록의 범위를 공중 납치.

let변수는 window전역 적으로 액세스 할 수 없으므로 객체 에서 액세스 할 수 없습니다.

function a(){
    { // this is the Max Scope for let variable
        let x = 12;
    }
    console.log(x);
}
a(); // Uncaught ReferenceError: x is not defined

사용할 때 var

var ES5의 변수에는 함수의 범위가 있으므로 변수는 함수 자체가 아닌 함수 내에서 유효합니다.

var변수는 window전역 적으로 액세스 할 수 없으므로 객체 에서 액세스 할 수 있습니다.

function a(){ // this is the Max Scope for var variable
    { 
        var x = 12;
    }
    console.log(x);
}
a(); // 12

더 알고 싶다면 아래에서 계속 읽으십시오.

범위에서 가장 유명한 인터뷰 질문 중 하나는 다음 letvar같이 정확한 사용법으로 충분할 수 있습니다.

사용할 때 let

for (let i = 0; i < 10 ; i++) {
    setTimeout(
        function a() {
            console.log(i); //print 0 to 9, that is literally AWW!!!
        }, 
        100 * i);
}

사용시 let 루프를 마다 변수의 범위가 지정되고 자체 사본 입니다.

사용할 때 var

for (var i = 0; i < 10 ; i++) {
    setTimeout(
        function a() {
            console.log(i); //print 10 times 10
        }, 
        100 * i);
}

이는 var모든 루프 반복에 대해 변수를 사용하고 범위를 지정하고 사본을 공유하기 때문입니다.


7

내가 사양을 올바르게 읽으면 let 고맙게도 개인 전용 멤버를 시뮬레이션하는 데 사용되는 자체 호출 기능 을 피할 수 있습니다 - 코드 가독성을 낮추고 디버깅을 복잡하게 만드는 인기있는 디자인 패턴 - 실제 코드 보호 또는 다른 이점을 추가하지 않는 다른 사람을 만족시키는 것을 제외하고- 의미를 원하면 사용을 중지하십시오. / rant

var SomeConstructor;

{
    let privateScope = {};

    SomeConstructor = function SomeConstructor () {
        this.someProperty = "foo";
        privateScope.hiddenProperty = "bar";
    }

    SomeConstructor.prototype.showPublic = function () {
        console.log(this.someProperty); // foo
    }

    SomeConstructor.prototype.showPrivate = function () {
        console.log(privateScope.hiddenProperty); // bar
    }

}

var myInstance = new SomeConstructor();

myInstance.showPublic();
myInstance.showPrivate();

console.log(privateScope.hiddenProperty); // error

'보기 개인 인터페이스를 에뮬레이션 '


즉시 호출 된 함수 표현식이 "코드 보호"를 제공하지 않고 수행하는 방법에 대해 자세히 설명 할 수 있습니까 let? (“자기 호출 기능”을 가진 IIFE를 의미한다고 가정합니다.)
Robert Siemer

그리고 왜 hiddenProperty생성자에서 설정 합니까? hiddenProperty“클래스”에는 모든 인스턴스에 대해 하나만 있습니다 .
Robert Siemer

6

가장 기본적인 용어로

for (let i = 0; i < 5; i++) {
  // i accessible ✔️
}
// i not accessible ❌

for (var i = 0; i < 5; i++) {
  // i accessible ✔️
}
// i accessible ✔️

⚡️ 샌드 박스는 ↓

let vs var 편집


4

일부 해킹 let:

1.

    let statistics = [16, 170, 10];
    let [age, height, grade] = statistics;

    console.log(height)

2.

    let x = 120,
    y = 12;
    [x, y] = [y, x];
    console.log(`x: ${x} y: ${y}`);

삼.

    let node = {
                   type: "Identifier",
                   name: "foo"
               };

    let { type, name, value } = node;

    console.log(type);      // "Identifier"
    console.log(name);      // "foo"
    console.log(value);     // undefined

    let node = {
        type: "Identifier"
    };

    let { type: localType, name: localName = "bar" } = node;

    console.log(localType);     // "Identifier"
    console.log(localName);     // "bar"

게터와 세터 let:

let jar = {
    numberOfCookies: 10,
    get cookies() {
        return this.numberOfCookies;
    },
    set cookies(value) {
        this.numberOfCookies = value;
    }
};

console.log(jar.cookies)
jar.cookies = 7;

console.log(jar.cookies)

이것이 무엇을 의미 let { type, name, value } = node;합니까? 3 가지 속성 유형 / 이름 / 값으로 새 객체를 생성하고 노드의 속성 값으로 초기화합니다.
AlainIb 2016 년

예제 3에서는 예외를 일으키는 노드를 다시 선언하고 있습니다. 이 모든 예제도 완벽하게 작동합니다 var.
Rehan Haider

4

let vs var. 범위 에 관한 것 입니다.

var 변수는 전역 적 이며 기본적으로 어디서나 액세스 할 수있는 반면 변수는 전역 적이 지 않으며 닫는 괄호로 묶을 때까지만 존재합니다.

아래의 예를보고 lion (let) 변수가 두 console.logs에서 어떻게 다르게 작동하는지 참고하십시오. 두 번째 console.log에서 범위를 벗어납니다.

var cat = "cat";
let dog = "dog";

var animals = () => {
    var giraffe = "giraffe";
    let lion = "lion";

    console.log(cat);  //will print 'cat'.
    console.log(dog);  //will print 'dog', because dog was declared outside this function (like var cat).

    console.log(giraffe); //will print 'giraffe'.
    console.log(lion); //will print 'lion', as lion is within scope.
}

console.log(giraffe); //will print 'giraffe', as giraffe is a global variable (var).
console.log(lion); //will print UNDEFINED, as lion is a 'let' variable and is now out of scope.

4

ES6는 var 대신에 두 개의 새로운 키워드 ( letconst )를 도입했습니다 .

블록 레벨 감속이 필요한 경우 var 대신 let 및 const를 사용할 수 있습니다.

아래 표는 var, let 및 const의 차이점을 요약 한 것입니다

여기에 이미지 설명을 입력하십시오


3

let은 es6의 일부입니다. 이러한 기능을 통해 차이점을 쉽게 설명 할 수 있습니다.

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // same variable!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // different variable
    console.log(x);  // 2
  }
  console.log(x);  // 1
}

3

아래는 'let'과 'var'이 범위에서 어떻게 다른지 보여줍니다.

let gfoo = 123;
if (true) {
    let gfoo = 456;
}
console.log(gfoo); // 123

var hfoo = 123;
if (true) {
    var hfoo = 456;
}
console.log(hfoo); // 456

gfoo의해 정의 let된는 전역 범위 에 있으며, 범위gfoo 내에서 다시 선언 if clause하고 변경된 범위 내에서 변수에 새 값이 할당 되면 전역 범위에 영향을 미치지 않습니다 .

반면 hfoo에 의해 정의는 var초기에 전역 범위 ,하지만 우리는 내부를 선언 할 때 다시 if clausevar에 선언을 다시 사용되었지만, 그것은, 글로벌 범위 hfoo을 고려합니다. 그리고 우리가 그 값을 다시 할당 할 때 우리는 전역 범위 hfoo도 영향을 받는다는 것을 알 수 있습니다. 이것이 주요 차이점입니다.


2

상술 한 바와 같이:

차이점은 범위입니다. var가까운 범위로되는 기능 블록let받는 범위가 가까운 바깥 블록 기능 블록보다 작을 수있다. 블록 외부에있는 경우 둘 다 전역입니다.

예 1 :

내 두 가지 예 모두에 함수가 myfunc있습니다. myfunc변수에 포함 myvar나는 경우 확인 내 첫 번째 예에서 10 등호를 myvar등호 10 ( myvar==10). 그렇다면 agian myvarvar키워드를 사용하여 변수를 선언하고 (이제 두 개의 myvar 변수가 있음) 새로운 값을 지정합니다 (20). 다음 줄에서는 콘솔에 값을 인쇄합니다. 조건부 블록 후에 다시 myvar콘솔에 값을 인쇄합니다 . 당신의 출력을 보면 myfunc, myvar값이 20로 동일있다.

키워드를 보자

예 2 :var 조건부 블록에서 키워드 를 사용하는 대신 두 번째 예에서는 keyword를 myvar사용하여 선언 let합니다. 지금은 호출 할 때 myfunc 나는 두 개의 서로 다른 출력을 얻을 : myvar=20myvar=10.

따라서 그 차이는 매우 간단합니다. 즉 범위입니다.


3
코드 그림을 게시하지 마십시오. 향후 사용자가 접근 할 수 없으며 접근성 문제가 있으므로 SO에 대한 나쁜 습관으로 간주됩니다. 또한이 답변은 다른 답변이 아직 해결하지 않은 내용을 추가하지 않습니다.
inostia

2

실행 컨텍스트가이 모든 것에서 중요하기 때문에 이러한 키워드를 실행 컨텍스트에 연결하려고합니다. 실행 컨텍스트에는 작성 단계와 실행 단계의 두 단계가 있습니다. 또한 각 실행 컨텍스트에는 가변 환경 및 외부 환경 (Lexical Environment)이 있습니다.

실행 컨텍스트의 생성 단계 동안 var, let 및 const는 주어진 실행 컨텍스트의 변수 환경에서 정의되지 않은 값으로 변수를 메모리에 저장합니다. 차이점은 실행 단계에 있습니다. var에 정의 된 변수에 값을 할당하기 전에 reference를 사용하면 정의되지 않습니다. 예외는 발생하지 않습니다.

그러나 let 또는 const로 선언 된 변수는 선언 될 때까지 참조 할 수 없습니다. 선언하기 전에 사용하려고하면 실행 컨텍스트의 실행 단계에서 예외가 발생합니다. 이제 변수는 실행 컨텍스트의 작성 단계에 의해 여전히 메모리에 남아 있지만 엔진에서는이를 사용할 수 없습니다.

function a(){
    b;
    let b;
}
a();
> Uncaught ReferenceError: b is not defined

var로 정의 된 변수를 사용하여 엔진이 현재 실행 컨텍스트의 변수 환경에서 변수를 찾을 수 없으면 범위 체인 (외부 환경)으로 이동하여 변수에 대한 외부 환경의 변수 환경을 확인합니다. 찾을 수없는 경우 스코프 체인을 계속 검색합니다. let과 const는 그렇지 않습니다.

let의 두 번째 기능은 블록 범위를 소개한다는 것입니다. 블록은 중괄호로 정의됩니다. 함수 블록, if 블록, 블록 등을 예로들 수 있습니다. 블록 내부에 let을 사용하여 변수를 선언하면 변수는 블록 내부에서만 사용할 수 있습니다. 실제로 for 루프 내에서와 같이 블록이 실행될 때마다 메모리에 새 변수가 생성됩니다.

ES6에는 변수 선언을위한 const 키워드도 도입되었습니다. const도 블록 범위입니다. let과 const의 차이점은 const 변수를 이니셜 라이저를 사용하여 선언해야한다는 점입니다. 그렇지 않으면 오류가 발생합니다.

마지막으로 실행 컨텍스트와 관련하여 var로 정의 된 변수는 'this'객체에 첨부됩니다. 전역 실행 컨텍스트에서는 브라우저의 창 개체가됩니다. let 또는 const의 경우에는 해당되지 않습니다.


2

나는 용어와 대부분의 예제가 약간 압도적이라고 생각한다. 내가 개인적으로 차이점을 가지고 있었던 주요 문제는 "블록"이 무엇인지 이해하는 것이다. 내가 깨달은 시점에서 블록은 IF문장을 제외한 중괄호가 될 것입니다 . {함수 또는 루프 의 여는 괄호 는 새로운 블록을 정의하며, 그 let안에 정의 된 }것은 동일한 것의 닫는 괄호 (함수 또는 루프) 후에 사용할 수 없습니다 . 이를 염두에두고 이해하기가 더 쉬워졌습니다.

let msg = "Hello World";

function doWork() { // msg will be available since it was defined above this opening bracket!
  let friends = 0;
  console.log(msg);

  // with VAR though:
  for (var iCount2 = 0; iCount2 < 5; iCount2++) {} // iCount2 will be available after this closing bracket!
  console.log(iCount2);
  
    for (let iCount1 = 0; iCount1 < 5; iCount1++) {} // iCount1 will not be available behind this closing bracket, it will return undefined
  console.log(iCount1);
  
} // friends will no be available after this closing bracket!
doWork();
console.log(friends);


1

이제 let다음을 사용하여 명령문 블록에 변수 범위를 더 잘 지정한다고 생각합니다 .

function printnums()
{
    // i is not accessible here
    for(let i = 0; i <10; i+=)
    {
       console.log(i);
    }
    // i is not accessible here

    // j is accessible here
    for(var j = 0; j <10; j++)
    {
       console.log(j);
    }
    // j is accessible here
}

사람들은 다른 언어, Java, C # 등과 같은 JavaScript에서 비슷한 범위를 갖도록 let을 사용하기 시작할 것이라고 생각합니다.

JavaScript의 범위 지정에 대해 명확하게 이해하지 못하는 사람들은 실수를 일찍 저 지르 곤했습니다.

를 사용하여 게양이 지원되지 않습니다 let.

이 접근 방식으로 JavaScript에 존재하는 오류가 제거됩니다.

를 참조하십시오 ES6에서 깊이 :하자 CONST이 더 잘 이해 할 수 있습니다.


그것에 대한 자세한 이해를 위해 링크 -davidwalsh.name/for-and-andinstinstlet
swaraj patil

1

이 기사는 var, let 및 const의 차이점을 명확하게 정의합니다.

const 식별자가 재 할당되지 않음을 나타내는 신호입니다.

let는 루프의 카운터 또는 알고리즘의 값 스왑과 같이 변수가 재 할당 될 수 있다는 신호입니다. 또한 변수가 정의 된 블록에서만 사용된다는 신호를 보냅니다. 항상 전체 포함 함수는 아닙니다.

varJavaScript에서 변수를 정의 할 때 사용 가능한 가장 약한 신호입니다. 변수는 재 할당되거나 재 할당되지 않을 수 있으며, 변수는 전체 기능 또는 블록 또는 루프의 목적으로 사용될 수도 있고 사용되지 않을 수도 있습니다.

https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75#.esmkpbg9b

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.