let和var一样也是用来定义变量,不同之处在于let是块级作用域,只在所定义的块级作用域中生效,一个花括号便是一个块级作用域

{var a="我是var定义的";let b="我是let定义的"}
console.log(a); //我是var定义的
console.log(b); //b is not defined

可以看出let定义的变量在全局作用域内并没有生效

如果我们在全局作用域中定义,试一下看在函数或者流程控制语句中是否会输出

let a="我是let定义的"
var b=0;
while(b<5){b++;console.log(a)}//⑤我是let定义的变量
if(true){console.log(a)}//我是let定义的变量

我们发现这样可以输出

如果我们反向来一下呢

for(let i=0;i<5;i++){
let a="流程控制语句花括号中的let";
var b="流程控制语句花括号中的var";
console.log(i)}
//0,1,2,3,4
console.log(a);
//a is not defined
console.log(b);
//流程控制语句中的var
for(var j=0;j<1;j++){
console.log(j)}
//
console.log(j);
//

我们发现let定义的变量不会被提升,只要有块级括号存在,它就只在该块级中有意义

如果在函数中呢

function test(){console.log(a)}() //报错

我们发现并不能输出

我们可以得出结论,流程控制语句中的变量均属于全局变量,但是在流程控制语句中的括号中定义则为块级,不会提升为全局变量

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

for(let i=0;i<3;i++){
let i="abc";
console.log(i)}
//abc,abc,abc

let在for循环声明的变量每一次循环的值都会被引擎内部记下,但是var声明的变量则会刷新覆盖掉上一次的值

var a=[];
for(var i=0;i<10;i++){
a[i]=function(){return i};}
console.log(a)//[f,f,f,f,f,f,f,f,f,f]
a.forEach((e)=>{console.log(e())})
//⑩10

我们可以看出,这种方式其实将未执行的函数push进数组了,当每次调用时候发现此刻的i早已经被循环覆盖掉,最终输出都为此刻的i值10

var a=[];
for(let i=0;i<10;i++){
a[i]=function(){return i};}
console.log(a)//[f,f,f,f,f,f,f,f,f,f]
a.forEach((e)=>{console.log(e())})
//0,1,2,3,4,5,6,7,8,9

但是对于let声明的变量,每一次引擎都会自动存储记录i的值,而不会覆盖掉,因此每次输出都是push当时的i值

let不存在变量提升,只有在定义后再使用才不会报错

console.log(a);var a=1;//undefined
console.log(b);let b=2;//报错

let具有强制性绑定变量的能力,原先var声明的变量,当被let重新声明的时候会被强制性绑定,原先var声明的所有被let所管辖的块级作用域里的变量均被let强制为自己声明的值,形成暂时性死区,let所处块级作用域中let声明之前的该变量均报错

var a=1;
{console.log(a);
let a=2;}
//a is not defined
var a=1;
{let a=2;
console.log(a);//
};
console.log(a)//
var a=1;
console.log(a);//
{let a=2;
console.log(a);//
};

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

{var a=0;
let a=1;
console.log(a)}//报错
{let a=0;
var a=1;
console.log(a)}//报错
{
let a=2;
let a=3;
console.log(a)}//报错
{let a=2;
console.log(a);
let a=3;}//报错

上面的最后一个例子可以看出当再次声明该变量之前调用的变量都会炸掉

我们可以看到let声明的变量可以引用块级作用域外面的函数

let a=f();
function f(){
return 1
}
console.log(a)//
{let a=f();
console.log(a)//
function f(){
return 1
}

const声明的变量为永恒变量,不能更改,而且声明以后必须初始化

const a;//报错
const b=1;
b=2//报错

const的作用域与let命令相同:只在声明所在的块级作用域内有效。
const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
const声明的常量,也与let一样不可重复声明。
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。

常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。

const foo={};
foo.prop=123;
console.log(foo.prop)//

常量a是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给a,就会报错。

const a=[];
a.push(1);
console.log(a)//[1]
console.log(a.length)//
a=[]//报错

再来验证以下引用

var a=1;
b=a;
console.log(b);//
a=2;
console.log(b)//
b=3;
console.log(a)//

可以看出var定义的变量,b=a时候,是直接复制了一份a,并不是a的引用

let a=1;
b=a;
console.log(b);//
a=2;
console.log(b);//
b=3;
console.log(a);//
console.log(b);//
var b=4;
console.log(b)//

可以看出let也一样
const也是复制一份

const a=1;
b=a;
console.log(b);//
b=3;
console.log(a);//
console.log(b);//
var b=4;
console.log(b)//

ES6中let和const详解的更多相关文章

  1. JS ES6中export和import详解

    1.Export 模块是独立的文件,该文件内部的所有的变量外部都无法获取.如果希望获取某个变量,必须通过export输出, // profile.js export var firstName = ' ...

  2. linux-2.6.26内核中ARM中断实现详解(转)

    转载:http://www.cnblogs.com/leaven/archive/2010/08/06/1794293.html 更多文档参见:http://pan.baidu.com/s/1dDvJ ...

  3. 关于 redux-saga 中 take 使用方法详解

    本文介绍了关于redux-saga中take使用方法详解,分享给大家,具体如下: 带来一个自己研究好久的API使用方法. redux-saga中effect中take这个API使用方式,用的多的是ca ...

  4. Postman中的Pre-request Scrip详解

    Postman中的Pre-request Scrip详解 一.Pre-request Scrip的简介 1.Pre-request Script是在请求发送之前需要执行的代码片段: 2.请求参数中包含 ...

  5. C#中string.format用法详解

    C#中string.format用法详解 本文实例总结了C#中string.format用法.分享给大家供大家参考.具体分析如下: String.Format 方法的几种定义: String.Form ...

  6. c++中vector的用法详解

    c++中vector的用法详解 vector(向量): C++中的一种数据结构,确切的说是一个类.它相当于一个动态的数组,当程序员无法知道自己需要的数组的规模多大时,用其来解决问题可以达到最大节约空间 ...

  7. 011-Scala中的apply实战详解

    011-Scala中的apply实战详解 object中的apply方法 class中的apply方法 使用方法 apply方法可以应用在类或者Object对象中 class类 必须要创建实例化的类对 ...

  8. C# WinForm 中 MessageBox的使用详解

    1.C# WinForm 中 MessageBox的使用详解:http://www.cnblogs.com/bq-blog/archive/2012/07/27/2611810.html

  9. JScript中的条件注释详解(转载自网络)

    JScript中的条件注释详解-转载 这篇文章主要介绍了JScript中的条件注释详解,本文讲解了@cc_on.@if.@set.@_win32.@_win16.@_mac等条件注释语句及可用于条件编 ...

随机推荐

  1. Linux CentOS 7 安装字体库 & 中文字体

    前言 报表中发现有中文乱码和中文字体不整齐(重叠)的情况,首先考虑的就是操作系统是否有中文字体,在CentOS 7中发现输入命令查看字体列表是提示命令无效: 如上图可以看出,不仅没有中文字体,连字体库 ...

  2. 【转】学习Python的19个资源

    原文链接:[译]学习Python编程的19个资源 用Python编写代码一点都不难,事实上它一直被赞誉为最容易学的编程语言.如果你准备学习web开发, Python是一个不错的开始,甚至想做游戏的话, ...

  3. python PIL/Pillow图像扩展、复制、粘贴处理

    http://blog.csdn.net/yuanyangsdo/article/details/60957685

  4. binding与属性

    Text="{Binding Path=SearchKeyWord, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" 将“源”显 ...

  5. SPOJ-CLEANRBT-状压dp

    CLEANRBT - Cleaning Robot #dynamic-programming #bfs Here, we want to solve path planning for a mobil ...

  6. UVA-11294 Wedding (2-SAT)

    题目大意:一张长桌,n对夫妻,编号为0~n,这些人要坐在长桌两侧,每对夫妻不能坐在同一侧.其中,有2*m个人相互讨厌,编号为0的夫妻中的妻子不愿意让对面那一侧中有两个相互吵过架的人,找一种排座位方案. ...

  7. (1) iOS开发之UI处理-预览篇

    不管是做iOS还是Android的开发,我想UI这块都是个大麻烦,任何客户端编程都是如此,我们要做的就是尽量减少我们工作的复杂度,这样才能更轻松的工作. 在iOS开发中Xcode虽然自带了强大的IB( ...

  8. Gruntjs提高生产力(一)

    gruntjs是一个基于nodejs的自动化工具,只要熟悉nodejs或者又一定js经验就可以熟练应用. 1. 安装 a. 保证已安装了nodejs,并带有npm b.安装客户端命令行工具,grunt ...

  9. CentOS6.6系统中安装配置Samba的教程

    Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成.SMB(Server Messages Block,信息服务块)是一种在局域网上共享文件和打印机的一种通 ...

  10. 初识async函数

    为什么会出现async函数 首先从大的方面来说,出现async函数时为了解决JS编程中的异步操作,再往具体说就是为了对以往异步编程方法的一种改进,也有人说仅仅只是Generator 函数的语法糖,这个 ...