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. maven笔记(1)

    maven环境搭建:http://www.cnblogs.com/fnng/archive/2011/12/02/2272610.html 项目管理利器(Maven)——常用的构建命令1. mvn - ...

  2. transform对定位元素的影响

    1.温故知新 absolute:生成绝对定位的元素,相对于除position:static 定位以外的第一个有定位属性的父元素进行定位,若父元素没有定位属性则相对于浏览器窗口的左上角定位,定位的元素不 ...

  3. 1-10 RHLE7 系统进程管理

    1.1-Linux进程管理 程序.进程.线程 程序:一组指令的集合    QQ 进程:程序的执行就是进程.也可以把进程看成一个独立的程序,在内存中有其对应的代码空间和数据空间,一个进程所拥有的数据和代 ...

  4. 二十五 Python分布式爬虫打造搜索引擎Scrapy精讲—Requests请求和Response响应介绍

    Requests请求 Requests请求就是我们在爬虫文件写的Requests()方法,也就是提交一个请求地址,Requests请求是我们自定义的 Requests()方法提交一个请求 参数: ur ...

  5. nyoj——弃九法

    A*B Problem 时间限制:1000 ms  |  内存限制:65535 KB 难度:2   描述 设计一个程序求出A*B,然后将其结果每一位相加得到C,如果C的位数大于等于2,继续将C的各位数 ...

  6. BZOJ 1005 [HNOI2008]明明的烦恼 ★(Prufer数列)

    题意 N个点,有些点有度数限制,问这些点可以构成几棵不同的树. 思路 [Prufer数列] Prufer数列是无根树的一种数列.在组合数学中,Prufer数列是由一个对于顶点标过号的树转化来的数列,点 ...

  7. 进程上下文频繁切换导致load average过高

    一.问题现象 现网有两台虚拟机主机95%的cpu处于idle状态,内存使用率也不是特别高,而主机的load average达到了40多. 二.问题分析 先在主机上通过top.free.ps.iosta ...

  8. hdu 5800 To My Girlfriend(背包变形)

    To My Girlfriend Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) ...

  9. 浅谈title属性与alt属性

    XHTML是CSS布局的基础,webjx.com一直强调XHTML知识的学习,重视语义和文档的结构.title 和alt 属性,给我最直观的感受就是,可以提高文档的适应性,并合理提高关键词密度.在XH ...

  10. Deep Learning深入浅出

    作者:Jacky Yang链接:https://www.zhihu.com/question/26006703/answer/129209540来源:知乎著作权归作者所有.商业转载请联系作者获得授权, ...