문제

ECMAScript 6 도입 그만큼 let 성명.

"로컬" 변수로 설명된다는 말을 들었지만, 이것이 로컬 변수와 어떻게 다르게 동작하는지 아직 잘 모르겠습니다. var 예어.

차이점은 무엇입니까?언제해야합니까? let 이상 사용되다 var?

도움이 되었습니까?

해결책

범위 규칙

주요 차이점은 범위 규칙입니다. 변수가 선언했습니다 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: 3 매번 콘솔로 출력되었습니다 funcs[j](); 익명 함수가 동일한 변수에 바인딩되었으므로 호출되었습니다.

사람들은 루프에서 올바른 값을 캡처하기 위해 즉시 호출 된 기능을 만들어야했지만 털이 많았습니다.

들어선

변수가 선언 된 반면 var 키워드는 블록의 상단에 "들어 섰다"는데, 이는 선언되기 전에도 동봉 범위에서 액세스 할 수 있음을 의미합니다.

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

run();

정의가 평가 될 때까지 변수가 초기화되지 않도록합니다. 초기화 전에 액세스하면 a ReferenceError. 변수는 블록의 시작부터 초기화가 처리 될 때까지 "Temporal Dead Zone"에 있다고합니다.

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

재분배

엄격한 모드에서 var 동일한 범위에서 동일한 변수를 다시 설명 할 수 있습니다. let SyntaxError를 올립니다.

'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

다른 팁

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>
<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 논쟁으로. 이러한 문제는 이제 사용하여 피할 수 있습니다 let 대신에 var 아래 코드에 표시된대로.

(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>
<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>

차이점은 무엇입니까? let 그리고 var?

  • a를 사용하여 정의 된 변수 var 진술은 전체적으로 알려져 있습니다 함수 함수의 시작부터 정의됩니다.*
  • a를 사용하여 정의 된 변수 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 루프에 대해서만 첫 번째로 알려져 있지만 전후에만 알려져 있지 않습니다. 그러나 우리의 변수 i 전체 기능에서 알려져 있습니다.

또한 블록 스코어 변수는 들어오지 않기 때문에 선언되기 전에 알려지지 않은 것을 고려하십시오. 또한 동일한 블록 내에서 동일한 블록 스코프 변수를 다시 사용할 수 없습니다. 이로 인해 블록 스코프 변수는 전 세계적으로 또는 기능적으로 범위가 지정된 변수보다 오류가 덜 발생합니다.이 변수는 생겨나 고 여러 선언의 경우 오류가 발생하지 않습니다.


사용하기에 안전합니까? let 오늘?

어떤 사람들은 미래에 우리는 우리가 LET 진술 만 사용하고 VAR 진술은 쓸모 없게 될 것이라고 주장 할 것입니다. 자바 스크립트 전문가 카일 심슨 썼다 그가 왜 그런지 믿지 않는지에 대한 매우 정교한 기사.

그러나 오늘날은 확실히 그렇지 않습니다. 사실, 우리는 실제로 사용하는 것이 안전한지 스스로에게 물어봐야합니다. let 성명. 해당 질문에 대한 답은 귀하의 환경에 따라 다릅니다.

  • 서버 측 JavaScript 코드를 작성하는 경우 (node.js), 당신은 안전하게 사용할 수 있습니다 let 성명.

  • 클라이언트 측 JavaScript 코드를 작성하고 브라우저 기반 트랜스 필러를 사용하는 경우 ( 추적 또는 바벨-스탠다론), 당신은 안전하게 사용할 수 있습니다 let 그러나 진술은 코드가 성능과 관련하여 최적이 될 수 있습니다.

  • 클라이언트 측 JavaScript 코드를 작성하고 노드 기반 트랜스 필러를 사용하는 경우 ( Traceur Shell 스크립트 또는 바벨), 당신은 안전하게 사용할 수 있습니다 let 성명. 브라우저는 전송 된 코드에 대해서만 알 수 있으므로 성능 단점은 제한되어야합니다.

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

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

Support table


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

브라우저가 지원하는 최신 개요 let 이 답변을 읽을 때의 진술, 이것 Can I Use 페이지.


* 전 세계 및 기능적 범위의 변수는 JavaScript 변수가 있기 때문에 선언되기 전에 초기화되고 사용할 수 있습니다. 들어 올렸다. 이것은 선언이 항상 범위의 맨 위에 있다는 것을 의미합니다.

** 블록 스코프 변수는 들어오지 않습니다

여기에 있습니다 설명의 설명 let 예어 몇 가지 예가 있습니다.

let 매우 좋아합니다 var. 주요 차이점은 a의 범위입니다 var 변수는 전체 둘레 기능입니다

이 테이블 Wikipedia에서 어떤 브라우저가 JavaScript 1.7을 지원하는지 보여줍니다.

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

허용 된 답변에는 요점이 없습니다.

{
  let a = 123;
};

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

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

루프 내부

다음으로 선언된 변수 let in 루프는 해당 루프 내에서만 참조될 수 있습니다.

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);
}

시간적 데드존

때문에 시간적 데드존, 다음을 사용하여 선언된 변수 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

다음은 두 가지의 차이점에 대한 예입니다 (크롬에 대해 방금 시작된 지원) :
enter image description here

보시다시피 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);

미묘한 차이점이 있습니다. let 스코핑은 가변 범위가 다른 언어에서 다소 다른 언어에서하는 것처럼 행동합니다.

예를 들어, 둘러싸는 블록으로 범위를 띠고 선언되기 전에 존재하지 않습니다.

그러나 그것은 주목할 가치가 있습니다 let 새로운 JavaScript 구현의 일부일 뿐이며 다양한 정도가 있습니다. 브라우저 지원.

  • 가변은 들어오지 않습니다

    let ~ 할 것이다 호이스트가 아닙니다 그들이 나타나는 블록의 전체 범위에. 대조적으로, var 아래처럼 들어 올릴 수 있습니다.

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

    사실, per @bergi, 둘 다 var 그리고 let 들어간다.

  • 쓰레기 수집

    블록 범위 let 메모리를 되찾기 위해 폐쇄 및 쓰레기 수집과 관련이 있습니다. 고려하다,

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

    그만큼 click 핸들러 콜백은 필요하지 않습니다 hugeData 변수. 이론적으로, 후 process(..) 거대한 데이터 구조 인 실행 hugeData 쓰레기를 모을 수 있습니다. 그러나 일부 JS 엔진은 여전히이 거대한 구조를 유지해야 할 수도 있습니다. click 함수는 전체 범위에 걸쳐 폐쇄됩니다.

    그러나 블록 범위는이 거대한 데이터 구조를 수집 한 쓰레기로 만들 수 있습니다.

    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 a) 초기 표현식에 대한 해당 이름을 가진 새로운 어휘 환경을 만듭니다. 여기.

주요 차이점은입니다 범위 차이 허락하다 내부에서만 사용할 수 있습니다 범위 For Loop과 같이 선언되었습니다. var 예를 들어 루프 외부에서 액세스 할 수 있습니다. 문서에서 MDN (MDN의 예도) :

허락하다 블록, 명령문 또는 사용되는 표현식에 대한 범위가 제한된 변수를 선언 할 수 있습니다. 이것은와 다릅니다 var Keyword는 전 세계적으로 또는 블록 범위에 관계없이 전체 기능으로 변수를 정의합니다.

변수가 선언했습니다 허락하다 포함 된 하위 블록뿐만 아니라 정의 된 블록을 범위로 사용하십시오. 이런 식으로, 허락하다 매우 좋아합니다 var. 주요 차이점은 a의 범위입니다 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 등을 사용하여 ECMA5로 전환하는 것이 좋습니다. 바벨 웹 사이트

다음은 다른 사람들이 이미 작성한 내용에 추가 할 예입니다. 기능 배열을 만들고 싶다고 가정 해 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

이 시간, i 각 반복에 반등합니다 for 고리. 각 함수는 이제 값을 유지합니다 i 기능 생성 시점에 adderFunctions 예상대로 작동합니다.

이제 두 가지 동작을 혼합하면 이미지가 더 새로운 것을 혼합하는 것이 권장되지 않는 이유를 알 수 있습니다. let 그리고 const 나이가 들었습니다 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.

차이는 범위 각각에 선언 된 변수 중

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

  1. let 변수는 그들에게만 볼 수 있습니다 가장 가까운 봉쇄 차단하다 ({ ... }).
  2. let 변수는 발생하는 코드 라인에서만 사용할 수 있습니다. ~ 후에 변수가 선언됩니다 (그래도 그들은 들어갔다!).
  3. let 변수는 후속에 의해 재고되지 않을 수 있습니다 var 또는 let.
  4. 글로벌 let 변수는 글로벌에 추가되지 않습니다 window 물체.
  5. let 변수입니다 사용하기 쉬운 폐쇄로 (그들은 원인이되지 않습니다 레이스 조건).

에 의해 부과 된 제한 let 변수의 가시성을 줄이고 예기치 않은 이름 충돌이 조기에 발견 될 가능성을 높입니다. 이를 통해 변수를 포함하여 추적하고 추론 할 수 있습니다. 도달 가능성(사용하지 않은 기억을 되 찾는 데 도움이).

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

var 루프에서 클로저를 사용할 때 (#5) 또는 코드에서 외부 가시 가능한 글로벌 변수를 선언 할 때 단일 바인딩 효과를 원한다면 여전히 유용 할 수 있습니다 (#4). 사용 var 수출의 경우 IF가 대체 될 수 있습니다 export 트랜스 필러 공간에서 핵심 언어로 마이그레이션합니다.

1. 가장 가까운 Enclosing 블록 외부에서 사용하지 않음 :이 코드 블록은 x 선언 된 블록 외부에서 발생합니다. let:

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

대조적으로, 동일한 예제 var 공장.

2. 선언 전에 사용하지 않음 :
이 코드 블록은 a를 던질 것입니다 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"5 번 :

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

다음 두 기능이 차이점을 보여 주길 바랍니다.

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
}

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].

함수 대 블록 범위 :

사이의 주요 차이점 var 그리고 let 그 변수는 다음과 같이 선언되었습니다 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라고 불립니다 var, 여전히 외부에서 액세스 할 수 있습니다 if 성명. 이 변수 foo 사용할 수 있습니다 어디에나 의 범위 내에서 testVar 기능.

변수 let:

두 번째 함수 일 때 testLet 변수 막대라고 불립니다 let, 내부에서만 액세스 할 수 있습니다 if 성명. 변수가 선언 되었기 때문입니다 let ~이다 블록 스코프 (블록이 곱슬 괄호 사이의 코드 인 경우 if{} , for{}, function{}).

let 변수는 들어오지 않습니다.

또 다른 차이점 var 그리고 let 선언 된 변수입니다 let 들어 오지 마십시오. 예를 들어이 행동을 설명하는 가장 좋은 방법이 있습니다.

변수 let ~하지 않다 들어 올리기 :

console.log(letVar);

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

변수 var 하다 들어 올리기 :

console.log(varVar);

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

글로벌 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 물체 (실제로 필요한 경우 항상 신중하게 고려하십시오).

또한 Visual Studio 2015에서 TypeScript 1.5에서 "VAR"은 블록에서 동일한 변수 이름의 여러 선언을 허용하고 "LET"는 그렇지 않은 것으로 보입니다.

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

var x = 1;
var x = 2;

이것은 :

let x = 1;
let x = 2;

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

사용할 때 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

아래에서 계속 읽으십시오

범위에서 가장 유명한 인터뷰 질문 중 하나는 정확한 사용으로 충분할 수 있습니다. let 그리고 var 아래;

사용할 때 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, 모든 루프 반복에 대해 변수는 스코핑되고 사본을 공유했습니다.

내가 사양을 읽으면 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:

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}`);

3.

    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"

getter and setter 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)

vs var. 그것은 전부입니다 범위.

VAR 변수는 전 세계적입니다 기본적으로 모든 곳에 액세스 할 수 있습니다 변수가 글로벌이 아닙니다 폐쇄 괄호가 그들을 죽일 때까지만 존재합니다.

아래의 예제를보고, 두 개의 콘솔에서 Lion (Let) 가변이 어떻게 다르게 행동하는지 주목하십시오. 두 번째 콘솔에서 범위가 떨어집니다.

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.

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
}

이전에는 JavaScript에는 두 가지 스코프, 즉 기능 및 전역이있었습니다. 와 함께 'let'키워드 JavaScript가 소개되었습니다 block-level 변수.

'하자'키워드를 완전히 이해하려면 ES6 : '하자'키워드가 JavaScript에서 변수를 선언합니다. 도움이 될 것입니다.

이제 나는 변수를 사용하여 진술 블록에 더 나은 범위를 범하는 것으로 생각합니다. 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 Here After를 사용하기 시작할 것이라고 생각합니다.

JavaScript의 범위에 대해 명확하게 이해하지 못한 사람들은 일찍 실수를 저지르는 데 사용되었습니다.

호이 스팅은 사용하지 않습니다 let.

이 접근법으로 JavaScript에있는 오류가 제거됩니다.

인용하다 ES6 깊이 : Let and Const 더 잘 이해하려면.

이 기사는 VAR, Let 및 Const의 차이점을 명확하게 정의합니다.

const 식별자가 재 할당되지 않는다는 신호입니다.

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

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

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

앞에서 말했다시피:

차이점은 범죄입니다. var 가장 가까운 곳으로 범위를 지정합니다 기능 블록 그리고 let is scoped to the 가장 가까운 봉쇄 블록, 기능 블록보다 작을 수 있습니다. 둘 다 블록 외부에있는 경우 둘 다 글로벌입니다.

예제 1 : 예제 1 : 예제 1 : 예제 1 : : 예제 1 : : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제 1 : 예제.

두 예에서는 기능이 있습니다 myfunc. myfunc 변수를 포함합니다 myvar 첫 번째 예에서 나는 myvar 10에서 1에 같습니다 (myvar==10). 그렇다면 Agian은 변수를 선언합니다 myvar (이제 두 개의 myvar 변수가 있습니다) 사용 var 키워드 및 새 값을 지정하십시오 (20). 다음 줄에서는 콘솔에서 그 값을 인쇄합니다. 조건부 블록 후 I의 값을 다시 인쇄합니다. myvar 내 콘솔에서. 출력을 보면 myfunc, myvar 값은 20에 해당합니다.

let keyword

2 : 예제 2 : 예제 2 : 예제 2 : : 예를 2 : 예를 실시 예제 2 : : : : : : : 예제 2 : : : 예제 2 : : : 예제 2 : : 예제 2 : 예제 2 : 예제 2 : 예제 2 : 예제.사용하는 대신 두 번째 예에서 var 조건부 블록의 키워드 나는 선언합니다 myvar 사용 let 키워드. 이제 내가 전화 할 때 myfunc 두 가지 다른 출력을 얻습니다. myvar=20 그리고 myvar=10.

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

enter image description here

이 이미지를 살펴보면 const 그리고 let 변수. 보시다시피, 변화를 시도 할 때 const 변수, 오류가 발생합니다 (상수 인 '이름'을 무시하려는 시도 '),하지만 살펴보십시오 let 변하기 쉬운...

먼저 우리는 선언합니다 let age = 33, 나중에 다른 값을 할당합니다 age = 34;, 괜찮습니다. 우리는 변경하려고 할 때 오류가 없습니다. let 변하기 쉬운

나는 용어와 대부분의 예가 약간 압도적이라고 생각합니다. 차이점과 개인적으로 가진 주요 문제는 "블록"이 무엇인지 이해하는 것입니다. 어느 시점에서 내가 깨달은 블록은 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);

현재 JavaScript에 대한 깊이있는 이해를 얻으려고 노력하고 있기 때문에 이미 논의 된 훌륭한 작품과 다른 관점에서 다른 세부 사항을 포함하는 간단한 연구를 공유 할 것입니다.

차이를 이해합니다 var 그리고 허락하다 우리가 차이를 이해하면 더 쉬울 수 있습니다 기능 그리고 블록 범위.

다음과 같은 경우를 고려해 봅시다.

(function timer() {
    for(var i = 0; i <= 5; i++) {
        setTimeout(function notime() { console.log(i); }, i * 1000);
    }
})();


   Stack            VariableEnvironment //one VariablEnvironment for timer();
                                       // when the timer is out - the value will be the same value for each call
5. [setTimeout, i]  [i=5] 
4. [setTimeout, i]  
3. [setTimeout, i]
2. [setTimeout, i]
1. [setTimeout, i]
0. [setTimeout, i]

####################    

(function timer() {
    for (let i = 0; i <= 5; i++) {
        setTimeout(function notime() { console.log(i); }, i * 1000);
    }
})();

   Stack           LexicalEnvironment - each iteration has a new lexical environment
5. [setTimeout, i]  [i=5]       
                      LexicalEnvironment 
4. [setTimeout, i]    [i=4]     
                        LexicalEnvironment 
3. [setTimeout, i]      [i=3]       
                         LexicalEnvironment 
2. [setTimeout, i]       [i=2]
                           LexicalEnvironment 
1. [setTimeout, i]         [i=1]
                             LexicalEnvironment 
0. [setTimeout, i]           [i=0]

언제 timer() an이라고 불립니다 executionContext 두 가지를 모두 포함 할 생성됩니다 가변 환경 그리고 모든 어휘성 환경 각 반복에 해당합니다.

그리고 더 간단한 예

기능 범위

function test() {
    for(var z = 0; z < 69; z++) {
        //todo
    }
    //z is visible outside the loop
}

블록 범위

function test() {
    for(let z = 0; z < 69; z++) {
        //todo
    }
    //z is not defined :(
}

이 키워드를 실행 컨텍스트에 연결하고 싶습니다. 실행 컨텍스트는이 모든 것에서 중요하기 때문입니다. 실행 컨텍스트에는 생성 단계와 실행 단계의 두 단계가 있습니다. 또한 각 실행 컨텍스트에는 가변 환경과 외부 환경 (어휘 환경)이 있습니다.

실행 컨텍스트의 생성 단계에서 Var, let and Const는 주어진 실행 컨텍스트의 가변 환경에서 정의되지 않은 값으로 메모리에 변수를 저장합니다. 차이는 실행 단계에 있습니다. 참조를 사용하면 값이 할당되기 전에 Var로 정의 된 변수를 사용하면 정의되지 않습니다. 예외는 제기되지 않습니다.

그러나 선언 될 때까지 LET 또는 Const로 선언 된 변수를 참조 할 수 없습니다. 선언되기 전에 사용하려고하면 실행 컨텍스트의 실행 단계에서 예외가 제기됩니다. 이제 변수는 여전히 실행 컨텍스트의 생성 단계를 제공하는 것이 여전히 메모리에있을 것이지만 엔진을 사용하면 사용할 수 없습니다.

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

VAR로 정의 된 변수를 사용하면 엔진이 현재 실행 컨텍스트의 가변 환경에서 변수를 찾을 수없는 경우 스코프 체인 (외부 환경)을 올라가서 변수의 외부 환경의 가변 환경을 확인합니다. 거기에서 찾을 수 없다면 스코프 체인을 계속 검색합니다. 이것은 Let and Const의 경우가 아닙니다.

Let의 두 번째 특징은 블록 범위를 소개한다는 것입니다. 블록은 곱슬 버팀대로 정의됩니다. 예제에는 기능 블록, 블록, 블록 등이 포함됩니다. 블록 내부로 변수를 선언 할 때 변수는 블록 내부에서만 사용할 수 있습니다. 실제로, for 루프 내와 같은 블록이 실행될 때마다 메모리에 새로운 변수가 생성됩니다.

ES6은 또한 변수를 선언하기위한 Const 키워드를 소개합니다. Const는 또한 블록 스코프입니다. LET와 CONS의 차이점은 이니셜 라이저를 사용하여 const 변수를 선언해야한다는 것입니다. 그렇지 않으면 오류가 발생합니다.

그리고 마지막으로, 실행 컨텍스트와 관련하여 Var로 정의 된 변수는 '이'객체에 첨부됩니다. 글로벌 실행 컨텍스트에서는 브라우저의 창 객체가됩니다. 이것은 Let 또는 Const의 경우가 아닙니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top