js ES6의 let 명령 사용에 대한 자세한 설명

零下一度
풀어 주다: 2017-07-09 09:34:56
원래의
1686명이 탐색했습니다.

ES6에는 변수 선언을 위한 새로운 let 명령이 추가되었습니다. 사용법은 var와 비슷하지만 선언된 변수는 let 명령이 있는 코드 블록 내에서만 유효합니다.

letCommand

기본 사용법

ES6에는 변수를 선언하는 데 사용되는 새로운 let 명령이 있습니다. 사용법은 var와 유사하지만 선언된 변수는 let 명령이 있는 코드 블록 내에서만 유효합니다.

{
 let a = 10;
 var b = 1;
}

a // ReferenceError: a is not defined.
b // 1
로그인 후 복사

위 코드는 코드 블록에 있으며 각각 let과 var를 사용하여 두 개의 변수를 선언합니다. 그런 다음 이 두 변수는 코드 블록 외부에서 호출됩니다. 결과적으로 let으로 선언된 변수는 오류를 보고하고 var로 선언된 변수는 올바른 값을 반환합니다. 이는 let으로 선언된 변수가 해당 변수가 위치한 코드 블록에서만 유효함을 보여줍니다.

루프 카운터의 경우 let 명령을 사용하는 것이 매우 적합합니다.

for (let i = 0; i < 10; i++) {}

console.log(i);
//ReferenceError: i is not defined
로그인 후 복사

위 코드에서 카운터 i는 for 루프 본문 내에서만 유효하며, 루프 외부에서 참조되면 오류가 보고됩니다.

다음 코드에서 var를 사용하면 최종 출력은 10입니다.

var a = [];
for (var i = 0; i < 10; i++) {
 a[i] = function () {
  console.log(i);
 };
}
a[6](); // 10
로그인 후 복사

위 코드에서 변수 i는 var로 선언되었으며 전역 범위에서 유효합니다. 따라서 반복될 때마다 새로운 i 값이 이전 값을 덮어쓰게 되어 최종 출력이 마지막 라운드의 i 값이 됩니다.

let을 사용하면 선언된 변수는 블록 수준 범위 내에서만 유효하며 최종 출력은 6입니다.

var a = [];
for (let i = 0; i < 10; i++) {
 a[i] = function () {
  console.log(i);
 };
}
a[6](); // 6
로그인 후 복사

위 코드에서 변수 i는 let에 의해 선언되었습니다. 현재 i는 이 주기에서만 유효하므로 각 주기의 i는 실제로 새로운 변수이므로 최종 출력은 6입니다.

변수 프로모션이 없습니다

let은 var와 같은 "변수 프로모션" 현상이 없습니다. 따라서 변수는 선언된 후에 사용해야 하며, 그렇지 않으면 오류가 보고됩니다.

console.log(foo); // 输出undefined
console.log(bar); // 报错ReferenceError

var foo = 2;
let bar = 2;
로그인 후 복사

위 코드에서는 var 명령어로 변수 foo를 선언하고 변수 승격이 발생합니다. 즉, 스크립트가 실행되기 시작하면 변수 foo가 이미 존재하지만 값이 없으므로 undefed가 출력됩니다. bar 변수는 let 명령으로 선언되며 변수 승격은 발생하지 않습니다. 이는 변수 bar가 선언되기 전에는 존재하지 않는다는 것을 의미하며, 이를 사용하면 오류가 발생합니다.

임시 데드 존

let 명령이 블록 수준 범위에 존재하는 한, 선언된 변수는 이 영역에 "바인딩"되며 더 이상 외부 영향의 영향을 받지 않습니다.

var tmp = 123;

if (true) {
 tmp = &#39;abc&#39;; // ReferenceError
 let tmp;
}
로그인 후 복사

위 코드에는 전역 변수 tmp가 있는데, let이 블록 수준 범위에서 지역 변수 tmp를 선언하면 후자가 블록 수준 범위를 바인딩하게 되므로 let이 변수를 선언하기 전에 오류가 발생합니다. tmp에 값을 할당할 때 보고됩니다.

ES6에서는 블록에 let 및 const 명령이 있는 경우 이 블록에서 이러한 명령으로 선언된 변수가 처음부터 닫힌 범위를 형성한다고 명확하게 규정합니다. 선언 전에 이러한 변수를 사용하면 오류가 발생합니다.

간단히 말하면 코드 블록 내에서는 let 명령을 사용하여 변수를 선언하기 전까지는 변수를 사용할 수 없습니다. 문법적으로는 이를 "임시 데드존"(TDZ)이라고 합니다.

if (true) {
 // TDZ开始
 tmp = &#39;abc&#39;; // ReferenceError
 console.log(tmp); // ReferenceError

 let tmp; // TDZ结束
 console.log(tmp); // undefined

 tmp = 123;
 console.log(tmp); // 123
}
로그인 후 복사

위 코드에서 let 명령이 tmp 변수를 선언하기 전에는 tmp 변수의 "dead zone"에 속합니다.

"임시 데드존"은 typeof가 더 이상 100% 안전한 작업이 아니라는 의미이기도 합니다.

typeof x; // ReferenceError
let x;
로그인 후 복사

위 코드에서 변수 x는 let 명령을 사용하여 선언되었으므로 선언되기 전에는 변수를 사용하는 한 오류가 보고됩니다. 따라서 typeof는 실행 시 ReferenceError를 발생시킵니다.

비교를 위해 변수가 전혀 선언되지 않은 경우 typeof를 사용해도 오류가 보고되지 않습니다.

typeof undeclared_variable // "undefined"
로그인 후 복사

위 코드에서 undeclared_variable은 존재하지 않는 변수 이름이고, 결과는 "정의되지 않음"입니다. 따라서 이전에는 typeofoperator가 100% 안전했으며 오류를 보고하지 않았습니다. 이것은 더 이상 사실이 아닙니다. 이 디자인은 모든 사람이 좋은 프로그래밍 습관을 들이도록 돕기 위한 것입니다. 변수는 선언된 후에 사용해야 합니다. 그렇지 않으면 오류가 보고됩니다.

일부 "데드 존"은 숨겨져 있어 찾기가 쉽지 않습니다.

function bar(x = y, y = 2) {
 return [x, y];
}
bar(); // 报错
로그인 후 복사

위 코드에서 bar 함수 호출 시 오류가 보고되는 이유(일부 구현에서는 오류를 보고하지 않을 수 있음)는 매개변수 x의 기본값이 다른 매개변수 y와 같고, y가 선언되지 않았기 때문입니다. 현재는 "데드 존"에 속합니다. y의 기본값이 x인 경우 x가 이때 선언되었으므로 오류가 보고되지 않습니다.

function bar(x = 2, y = x) {
 return [x, y];
}
bar(); // [2, 2]
로그인 후 복사

ES6에서는 주로 런타임 오류를 줄이고 변수가 선언되기 전에 사용되어 예상치 못한 동작이 발생하는 것을 방지하기 위해 임시 데드존과 let 및 const 문에서 변수 승격이 발생하지 않도록 규정합니다. 이러한 오류는 ES5에서 매우 일반적이며, 이제 이 조항을 사용하면 이러한 오류를 쉽게 피할 수 있습니다.

간단히 말하면, 임시 데드존의 본질은 현재 범위에 들어가자마자 사용하려는 변수가 이미 존재하지만, 해당 변수를 해당 라인까지만 얻어서 사용할 수 없다는 것입니다. 변수를 선언하는 코드가 나타납니다.

중복 선언은 허용되지 않습니다.

let은 동일한 범위에서 동일한 변수의 중복 선언을 허용하지 않습니다.

// 报错
function () {
 let a = 10;
 var a = 1;
}

// 报错
function () {
 let a = 10;
 let a = 1;
}
로그인 후 복사

따라서 함수 내에서 매개변수를 다시 선언할 수 없습니다.

function func(arg) {
 let arg; // 报错
}

function func(arg) {
 {
  let arg; // 不报错
 }
}
로그인 후 복사

블록 수준 범위

블록 수준 범위가 필요한 이유는 무엇인가요?

ES5에는 전역 범위와 기능 범위만 있고 블록 수준 범위가 없으므로 불합리한 시나리오가 많이 발생합니다.

첫 번째 시나리오에서는 내부 변수가 외부 변수를 덮어쓸 수 있습니다.

var tmp = new Date();

function f() {
 console.log(tmp);
 if (false) {
  var tmp = "hello world";
 }
}

f(); // undefined
로그인 후 복사

上面代码中,函数f执行后,输出结果为undefined,原因在于变量提升,导致内层的tmp变量覆盖了外层的tmp变量。

第二种场景,用来计数的循环变量泄露为全局变量。

var s = &#39;hello&#39;;

for (var i = 0; i < s.length; i++) {
 console.log(s[i]);
}

console.log(i); // 5
로그인 후 복사

上面代码中,变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。

ES6的块级作用域

let实际上为JavaScript新增了块级作用域。

function f1() {
 let n = 5;
 if (true) {
  let n = 10;
 }
 console.log(n); // 5
}
로그인 후 복사

上面的函数有两个代码块,都声明了变量n,运行后输出5。这表示外层代码块不受内层代码块的影响。如果使用var定义变量n,最后输出的值就是10。

ES6允许块级作用域的任意嵌套。

{{{{{let insane = &#39;Hello World&#39;}}}}};
로그인 후 복사

上面代码使用了一个五层的块级作用域。外层作用域无法读取内层作用域的变量。

{{{{
 {let insane = &#39;Hello World&#39;}
 console.log(insane); // 报错
}}}};
로그인 후 복사

内层作用域可以定义外层作用域的同名变量。

{{{{
 let insane = &#39;Hello World&#39;;
 {let insane = &#39;Hello World&#39;}
}}}};
로그인 후 복사

块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了。

// IIFE 写法
(function () {
 var tmp = ...;
 ...
}());

// 块级作用域写法
{
 let tmp = ...;
 ...
}
로그인 후 복사

块级作用域与函数声明

函数能不能在块级作用域之中声明,是一个相当令人混淆的问题。

ES5规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。

// 情况一
if (true) {
 function f() {}
}

// 情况二
try {
 function f() {}
} catch(e) {
}
로그인 후 복사

上面代码的两种函数声明,根据ES5的规定都是非法的。

但是,浏览器没有遵守这个规定,为了兼容以前的旧代码,还是支持在块级作用域之中声明函数,因此上面两种情况实际都能运行,不会报错。不过,“严格模式”下还是会报错。

// ES5严格模式
&#39;use strict&#39;;
if (true) {
 function f() {}
}
// 报错
로그인 후 복사

ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。


// ES6严格模式
&#39;use strict&#39;;
if (true) {
 function f() {}
}
// 不报错
로그인 후 복사

ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。

function f() { console.log(&#39;I am outside!&#39;); }
(function () {
 if (false) {
  // 重复声明一次函数f
  function f() { console.log(&#39;I am inside!&#39;); }
 }

 f();
}());
로그인 후 복사

上面代码在 ES5 中运行,会得到“I am inside!”,因为在if内声明的函数f会被提升到函数头部,实际运行的代码如下。

// ES5版本
function f() { console.log(&#39;I am outside!&#39;); }
(function () {
 function f() { console.log(&#39;I am inside!&#39;); }
 if (false) {
 }
 f();
}());
로그인 후 복사

ES6 的运行结果就完全不一样了,会得到“I am outside!”。因为块级作用域内声明的函数类似于let,对作用域之外没有影响,实际运行的代码如下。

// ES6版本
function f() { console.log(&#39;I am outside!&#39;); }
(function () {
 f();
}());
로그인 후 복사

很显然,这种行为差异会对老代码产生很大影响。为了减轻因此产生的不兼容问题,ES6在附录B里面规定,浏览器的实现可以不遵守上面的规定,有自己的行为方式。

允许在块级作用域内声明函数。
函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
同时,函数声明还会提升到所在的块级作用域的头部。
注意,上面三条规则只对ES6的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作let处理。

前面那段代码,在 Chrome 环境下运行会报错。

// ES6的浏览器环境
function f() { console.log(&#39;I am outside!&#39;); }
(function () {
 if (false) {
  // 重复声明一次函数f
  function f() { console.log(&#39;I am inside!&#39;); }
 }

 f();
}());
// Uncaught TypeError: f is not a function
로그인 후 복사

上面的代码报错,是因为实际运行的是下面的代码。

// ES6的浏览器环境
function f() { console.log(&#39;I am outside!&#39;); }
(function () {
 var f = undefined;
 if (false) {
  function f() { console.log(&#39;I am inside!&#39;); }
 }

 f();
}());
// Uncaught TypeError: f is not a function
로그인 후 복사

考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。

// 函数声明语句
{
 let a = &#39;secret&#39;;
 function f() {
  return a;
 }
}

// 函数表达式
{
 let a = &#39;secret&#39;;
 let f = function () {
  return a;
 };
}
로그인 후 복사

另外,还有一个需要注意的地方。ES6的块级作用域允许声明函数的规则,只在使用大括号的情况下成立,如果没有使用大括号,就会报错。

// 不报错
&#39;use strict&#39;;
if (true) {
 function f() {}
}

// 报错
&#39;use strict&#39;;
if (true)
 function f() {}
로그인 후 복사

do 表达式

本质上,块级作用域是一个语句,将多个操作封装在一起,没有返回值。

{
 let t = f();
 t = t * t + 1;
}
로그인 후 복사

上面代码中,块级作用域将两个语句封装在一起。但是,在块级作用域以外,没有办法得到t的值,因为块级作用域不返回值,除非t是全局变量。

现在有一个提案,使得块级作用域可以变为表达式,也就是说可以返回值,办法就是在块级作用域之前加上do,使它变为do表达式。


let x = do {
 let t = f();
 t * t + 1;
};
로그인 후 복사

上面代码中,变量x会得到整个块级作用域的返回值。

JavaScript ES6 的 let 和 var 的比较

在javascript 1.7中, let 关键词被添加进来, 我听说它声明之后类似于”本地变量“, 但是我仍然不确定它和 关键词 var 的具体区别。

回答:
不同点在于作用域, var关键词的作用域是最近的函数作用域(如果在函数体的外部就是全局作用域), let 关键词的作用域是最接近的块作用域(如果在任何块意外就是全局作用域),这将会比函数作用域更小。
同样, 像var 一样, 使用let 声明的变量也会在其被声明的地方之前可见。

下面是Demo 例子。

全局(Global)

当在函数体之外它们是平等的。

let me = &#39;go&#39;; //globally scoped 
var i = &#39;able&#39;; //globally scoped
로그인 후 복사

函数(Function)
当瞎下面这种, 也是平等的。

function ingWithinEstablishedParameters() { 
  let terOfRecommendation = &#39;awesome worker!&#39;; //function block scoped 
  var sityCheerleading = &#39;go!&#39;; //function block scoped 
};
로그인 후 복사

块(Block)
这是不同点, let 只是在 for 循环中, var 却是在整个函数都是可见的。

function allyIlliterate() { 
  //tuce is *not* visible out here 
 
  for( let tuce = 0; tuce < 5; tuce++ ) { 
    //tuce is only visible in here (and in the for() parentheses) 
  }; 
 
  //tuce is *not* visible out here 
}; 
 
function byE40() { 
  //nish *is* visible out here 
 
  for( var nish = 0; nish < 5; nish++ ) { 
    //nish is visible to the whole function 
  }; 
 
  //nish *is* visible out here 
};
로그인 후 복사

위 내용은 js ES6의 let 명령 사용에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿