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
키워드로 선언 된 변수 는 호이 스팅 ( 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
답변
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
인수로 전달 하는 것입니다. 이러한 문제는 다음을 사용하여 피할 수도 있습니다.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>
<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>
답변
차이 무엇 let
과 var
?
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 변수가 들어 있기 때문에 전역 및 기능적으로 범위가 지정된 변수를 선언하기 전에 초기화하고 사용할 수 있습니다 .이것은 선언이 항상 범위의 맨 위에 있다는 것을 의미합니다.
(**) 블록 범위 변수는 게양되지 않습니다
답변
다음 은 몇 가지 예와 함께 키워드에 대한 설명입니다let
.
let
매우 유사하게 작동합니다var
. 가장 큰 차이점은var
변수 의 범위 가 전체 둘러싸는 함수라는 것입니다
Wikipedia 의이 표 는 Javascript 1.7을 지원하는 브라우저를 보여줍니다.
Mozilla 및 Chrome 브라우저 만 지원합니다. IE, Safari 및 잠재적으로 다른 사람들은 그렇지 않습니다.
답변
수락 된 답변에 요점이 없습니다.
{
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);
}
일시적 데드 존
일시적인 데드 존 (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
답변
다음은이 둘의 차이점에 대한 예입니다 (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);