一、基本语法-let命令

(1)ES6新增了let命令,用来声明变量。所声明的变量,只在let命令所在的代码块内有效。

  循环的计数器,就很合适使用let命令。计数器i只在for循环体内有效,在循环体外引用就会报错。

  另外,for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

(2)不存在变量提升

  var命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined

  为了纠正这种现象,let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。  

// var 的情况
console.log(foo); // 输出undefined
var foo = 2; // let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;//在声明它之前,变量bar是不存在的,这时如果用到它,就会抛出一个错误。

(3)暂时性死区(TDZ)

  只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。ES6 明确规定,如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

  暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError let tmp; // TDZ结束
console.log(tmp); // undefined tmp = 123;
console.log(tmp); // 123

(4)不允许重复声明

  let不允许在相同作用域内,重复声明同一个变量。

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

 二、块级作用域

(1)为什么需要块级作用域?

  ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。

  第一种场景,内层变量可能会覆盖外层变量。

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

var s = 'hello';

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
//运行后输出 5,这表示外层代码块不受内层代码块的影响。
//如果两次都使用var定义变量n,最后输出的值才是 10。
}

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

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

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

// IIFE 写法
(function () {
var tmp = ...;
...
}()); // 块级作用域写法
{
let tmp = ...;
...
}

四、块级作用域与函数声明

  ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。但是,浏览器没有遵守这个规定,为了兼容以前的旧代码,还是支持在块级作用域之中声明函数。

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

function f() { console.log('I am outside!'); }
(function () {
if (false) {
// 重复声明一次函数f
function f() { console.log('I am inside!'); }
}
f();
}()); //上面代码在 ES5 中运行,会得到“I am inside!”,因为在if内声明的函数f会被提升到函数头部
//ES6 就完全不一样了,理论上会得到“I am outside! ,因为块级作用域内声明的函数类似于let,对作用域之外没有影响。
//但是,真的在 ES6 浏览器中运行一下上面的代码,是会报错的, //原来,如果改变了块级作用域内声明的函数的处理规则,显然会对老代码产生很大影响。为了减轻因此产生的不兼容问题,浏览器的实现可以不遵守上面的规定,
//有自己的行为方式。

  浏览器规则:

    - 允许在块级作用域内声明函数。

    - 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。

    - 同时,函数声明还会提升到所在的块级作用域的头部。

  tips:上面三条规则只对 ES6 的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作let处理。

  根据这三条规则,在浏览器的 ES6 环境中,块级作用域内声明的函数,行为类似于var声明的变量。

// 浏览器的 ES6 环境
function f() { console.log('I am outside!'); }
(function () {
if (false) {
// 重复声明一次函数f
function f() { console.log('I am inside!'); }
}
f();
}());
// Uncaught TypeError: f is not a function

上面的代码在符合 ES6 的浏览器中,都会报错,因为实际运行的是下面的代码。

// 浏览器的 ES6 环境
function f() { console.log('I am outside!'); }
(function () {
var f = undefined;
if (false) {
function f() { console.log('I am inside!'); }
} f();
}());
// Uncaught TypeError: f is not a function

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

// 函数声明语句
{
let a = 'secret';
function f() {
return a;
}
} // 函数表达式
{
let a = 'secret';
let f = function () {
return a;
};
}

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

// 不报错
'use strict';
if (true) {
function f() {}
} // 报错
'use strict';
if (true)
function f() {}

  tips:详情参考ECMAScript 6 入门参考

ECMAScript6 入门教程 初学记录let命令 块级作用域的更多相关文章

  1. Docker入门教程(二)命令

    Docker入门教程(二)命令 [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第二篇,介绍了Docker的基本命令以及命令的用法和功能. 在Docker ...

  2. ES6标准入门 第二章:块级作用域 以及 let和const命令

    一.块级作用域 1.为什么需要块级作用域? ES5中只有全局作用域和函数作用域,带来很多不合理的场景. (1)内层变量可能会覆盖外层变量: var tem = new Date(); function ...

  3. let命令和块级作用域

    学习了阮一峰老师的ES6,http://es6.ruanyifeng.com/,收益良多. 一.let命令1.概念:let命令用于声明变量,和var类似,但是使用let命令所声明的变量只有在该变量所在 ...

  4. ES6入门一:块级作用域(let&const)、spread展开、rest收集

    let声明 const声明 块级作用域 spread/rest 一.let声明与块作用域 在ES6之前,JavaScript中的作用域基本单元就是function.现在有了let就可以创建任意块的声明 ...

  5. ES6-let、const和块级作用域

    1.介绍 总的来说,ES6是在ES2015的基础上改变了一些书写方式,开放了更多API,这样做的目的最终还是为了贴合实际开发的需要.如果说一门编程语言的诞生是天才的构思和实现,那它的发展无疑就是不断填 ...

  6. ES6之块级作用域

    一.前言 在ECMAScript6(以下简称ES6)之前,ECMAScript的作用域只有两种: 1.  全局作用域: 2.  函数作用域. 正是因为有这两种作用域,所以在JavaScript中出现一 ...

  7. ES6的 let const 以及块级作用域

    let声明变量 用法类似于var,但是所声明的变量只在let所在的代码块内有效. 1 . 在ES6环境下,let声明的变量不能在声明之前调用. 例: console.log(i); //会报错,这叫做 ...

  8. for循环中let与var的区别,块级作用域如何产生与迭代中变量i如何记忆上一步的猜想

    我在前一篇讨论let与var区别的博客中,顺带一笔带过了let与var在for循环中的不同表现,虽然解释了是块级作用域的影响,但具体是怎么去影响的呢,我尝试的去理解了下,这篇博客主要从for循环步骤拆 ...

  9. 闭包和let块级作用域

    还是先从一个题目开始: 写一个隔1s输出数组的一项的函数. 如果可以用ES6语法,则可以这么写: function print (arr) { for (let i = 0; i < arr.l ...

随机推荐

  1. SpringBoot系统列 2 - 配置文件,多环境配置(dev,qa,online)

    实现项目的多环境配置的方法有很多,比如通过在Pom.xml中配置profiles(最常见) 然后在Install项目打War包的时候,根据需求打不同环境的包,如图: 这种配置多环境的方法在SSM框架中 ...

  2. Spring-Cloud-Config学习笔记(一):使用本地存储

    简介 Spring Cloud Config为分布式系统中的外部配置提供服务器和客户端支持.使用Config Server,您可以为所有环境中的应用程序管理其外部属性.它非常适合spring应用,也可 ...

  3. Adding ASP.NET MVC5 Identity Authentication to an existing project

    Configuring Identity to your existing project is not hard thing. You must install some NuGet package ...

  4. 9. Oracle DataGuard的介绍

    一. Oracle DataGuard简介 Oracle DataGuard:简称DG.是由一个Primary Database(主库)和一个或者多个Standby Database(备库)组成.对O ...

  5. 防止vue文件中的样式出现‘污染’情况(html5 scoped特性)

    近期在项目中出现了vue样式污染的情况: 一个页面刚进去时样式不正常,刷新之后,样式才才达到预期那样 在vue中,如果把样式写在vue文件的 style中,可能会出现样式污染的情况,这是要把写样式的标 ...

  6. Strassen 矩阵相乘算法(转)

    偶尔在算法课本上面看到矩阵相乘的算法,联想到自己曾经在蓝桥杯系统上曾经做过一道矩阵相乘的题目,当时用的是普通的矩阵相乘的方法,效率极低,勉强通过编译.所以决定研究一下Strassen矩阵相乘算法,由于 ...

  7. Wooden Sticks---(贪心)

    Problem Description There is a pile of n wooden sticks. The length and weight of each stick are know ...

  8. shell 脚本的编写

    创建一个shell文件 1. 创建一个.sh文件 2. 文件第一行声明shell编译器路径  #!/bin/bash 3. 修改文件权限 chmod 777 文件名    或  /bin/bash  ...

  9. Intellij IDEA 生成返回值对象快捷键

    在编写一行JAVA语句时,有返回值的方法已经决定了返回对象的类型和泛型类型,我们只需要给这个对象起个名字就行. 如果使用快捷键生成这个返回值,我们就可以减少不必要的打字和思考,专注于过程的实现. 步骤 ...

  10. JAVAMail邮件服务器

    SMTP:simple mail transfer protocol(简单邮件传输协议),是internate传输mail的基本协议,也是TCP/IP协议组成员, POP3:邮局协议第三版,是inte ...