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. 【程序员笔试面试必会——排序①】Python实现 冒泡排序、选择排序、插入排序、归并排序、快速排序、堆排序、希尔排序

    最近在准备笔试题和面试题,把学到的东西整理出来,一来是给自己留个笔记,二来是帮助大家学习. 题目: 给定一个int数组A及数组的大小n,请返回排序后的数组. 测试样例:  输入:[1,2,3,5,2, ...

  2. Python 使用sys模块

      你已经学习了如何在你的程序中定义一次函数而重用代码.如果你想要在其他程序中重用很多函数,那么你该如何编写程序呢?你可能已经猜到了,答案是使用模块.模块基本上就是一个包含了所有你定义的函数和变量的文 ...

  3. 获取CPU和内存的使用率

    1.获取CPU的使用率 主要就是一个计算. int CUseRate::GetCPUUseRate() //获取CPU使用率 { ; FILETIME ftIdle, ftKernel, ftUser ...

  4. Ansible 小手册系列 十一(变量)

    变量名约束 变量名称应为字母,数字和下划线. 变量应始终以字母开头. 变量名不应与python属性和方法名冲突. 变量使用 通过命令行传递变量(extra vars) ansible-playbook ...

  5. day5-os、sys模块

    一.概述 开发运维相关支撑系统现今已成为Devops下的一大热门领域,Python在这方面也有着自己独到的优势.这类场景以及其他一些场景下,需要调用一些操作系统的接口,这就涉及到今天要讲述的OS模块和 ...

  6. 弄懂flex布局

    目前在不考虑IE以及低端安卓机(4.3-)的兼容下,已经可以放心使用flex进行布局了.什么是flex布局以及它的好处,这里就不再赘述. 在这篇文章里,想说说flex布局的属性语法及其细节.那么网上也 ...

  7. 多进程回声服务器/客户端【linux】

    并发服务器端 #include <unistd.h> #include <stdio.h> #include <sys/wait.h> #include <c ...

  8. linux FTP 操作

    1.登陆: ftp 172.xxx.xxx.xxx 按提示输入用户名和密码 2.上传: 单个文件:put /路径/文件名 批量: 输入 prom 此命令是关闭交互(否则总是询问你是否要上传) 输入下载 ...

  9. bzip2压缩 解压缩

    压缩/解压缩压缩/解压缩之后的文件名称 必须是bz2 首先是  -z   压缩文件-d 解压缩!

  10. PHP错误Parse error: syntax error, unexpected end of file in test.php on line 12解决方法

    出现这个错误的原因就是语法错误,肯定是PHP程序的书写不规范造成,PHP语句标识符错了,没有在php.ini中开启短标签!八成是这个原因,啊啊啊! 今天在写PHP程序的时候总是出现这样的错误:Pars ...