let与const

ES2015(ES6)新增加了两个重要的JavaScript关键字: letconst

块级作用域

代码块内如果存在let或者const,代码块会对这些命令声明的变量从块的开始就形成一个封闭作用域。

{
let a = 1;
var b = 2;
function s(){return a;}
console.dir(s);
/*
...
[[Scopes]]: Scopes[2]
0: Block {a: 1}
1: Global ...
*/
}
// 此处不能使用 a ,a 是块级作用域
// 此处可以使用 b , b 在此处是全局作用域

[[Scopes]]是保存函数作用域链的对象,是函数的内部属性无法直接访问,[[Scopes]]中可以看到出现了一个Block块级作用域,这使得let特别适合在for中使用,在ECMAScript 2015引入let关键字之前,只有函数作用域和全局作用域,函数作用域中又可以继续嵌套函数作用域,在for并未具备局部作用域,于是有一个常见的闭包创建问题。

function counter(){
var arr = [];
for(var i = 0 ; i < 3 ; ++i){
arr[i] = function(){
return i;
}
}
return arr;
} var coun = counter();
for(var i = 0 ; i < 3 ; ++i){
console.log(coun[i]()); // 3 3 3
}

可以看到运行输出是3 3 3,而并不是期望的0 1 2,原因是这三个闭包在循环中被创建的时候,共享了同一个词法作用域,这个作用域由于存在一个ivar声明,由于变量提升,具有函数作用域,当执行闭包函数的时候,由于循环早已执行完毕,i已经被赋值为3,所以打印为3 3 3,可以使用let关键字声明i来创建块级作用域解决这个问题

function counter(){
var arr = [];
for(let i = 0 ; i < 3 ; ++i){
arr[i] = function(){
return i;
}
}
return arr;
} var coun = counter();
for(var i = 0 ; i < 3 ; ++i){
console.log(coun[i]()); // 0 1 2
}

当然也可以使用匿名函数新建函数作用域来解决

function counter(){
var arr = [];
for(var i = 0 ; i < 3 ; ++i){
(function(i){
arr[i] = function(){
return i;
}
})(i);
}
return arr;
} var coun = counter();
for(var i = 0 ; i < 3 ; ++i){
console.log(coun[i]()); // 0 1 2
}

一次声明

同一作用域内letconst只能声明一次,var可以声明多次

let a = 1;
let a = 1; //Uncaught SyntaxError: Identifier 'a' has already been declared const b = 1;
const b = 1; //Uncaught SyntaxError: Identifier 'b' has already been declared

暂时性死区

当使用letconst生成块级作用域时,代码块会对这些命令声明的变量从块的开始就形成一个封闭作用域,代码块内,在声明变量之前使用它会报错,称为暂时性死区。

{
console.log(a); // Uncaught ReferenceError: Cannot access 'a' before initialization
let a =1;
}

变量提升

letconst也存在变量提升,在ES6的文档中出现了var/let hoisting字样,也就是说官方文档说明letvar一样,都存在变量提升,但是与var的变量提升有所不同

let 的「创建」过程被提升了,但是初始化没有提升。
var 的「创建」和「初始化」都被提升了。
function 的「创建」「初始化」和「赋值」都被提升了。

stackoverflow中比较有说服力的例子

x = "global";
// function scope:
(function() {
x; // not "global" var/let/… x;
}());
// block scope (not for `var`s):
{
x; // not "global" let/const/… x;
}

js中无论哪种形式声明var,let,const,function,function*,class都会存在提升现象,不同的是,var,function,function*的声明会在提升时进行初始化赋值为 undefined,因此访问这些变量的时候,不会报ReferenceError异常,而使用let,const,class声明的变量,被提升后不会被初始化,这些变量所处的状态被称为temporal dead zone,此时如果访问这些变量会抛出ReferenceError异常,看上去就像没被提升一样。

https://blog.csdn.net/jolab/article/details/82466362
https://www.jianshu.com/p/0f49c88cf169
https://stackoverflow.com/questions/31219420/are-variables-declared-with-let-or-const-not-hoisted-in-es6

window

在全局作用域中使用var直接声明变量或方法等会挂载到window对象上,letconst声明变量或方法等会保存在Script作用域中

var a = 1;
let b = 2;
const c = 3; console.log(window.a); // 1
console.log(window.b); // undefined
console.log(window.c); // undefined
let a = 1;
{
let b = 2;
function s(){return a + b;}
console.dir(s);
/*
...
[[Scopes]]: Scopes[3]
0: Block {b: 2}
1: Script {a: 1}
2: Global ...
*/
}

初始化

varlet在声明时可以不赋初值,const必须赋初值

var a;
let b;
const c; //Uncaught SyntaxError: Missing initializer in const declaration

只读常量

const用以声明一个只读常量,初始化后值不可再修改

const a = 1;
a = 2; // Uncaught TypeError: Assignment to constant variable.

const其实保证的不是变量的值不变,而是保证变量指向的内存地址所保存的数据不允许改动。对于简单类型numberstringbooleanSymbol,值就保存在变量指向的那个内存地址,因此const 声明的简单类型变量等同于常量。而复杂类型objectarrayfunction,变量指向的内存地址其实是保存了一个指向实际数据的指针,所以const只能保证指针是固定的,至于指针指向的数据结构变不变就无法控制了。

const a = {};
console.log(a); // {}
a.s = function(){}
console.log(a); // {s: ƒ}

每日一题

https://github.com/WindrunnerMax/EveryDay

参考

ES6新特性 https://github.com/WindrunnerMax/EveryDay/blob/master/JavaScript/ES6%E6%96%B0%E7%89%B9%E6%80%A7.md
Js变量提升 https://github.com/WindrunnerMax/EveryDay/blob/master/JavaScript/JS%E5%8F%98%E9%87%8F%E6%8F%90%E5%8D%87.md

let与const的更多相关文章

  1. openssl 1.1.1 reference

    openssl 1.1.1 include/openssl aes.h: # define HEADER_AES_H aes.h: # define AES_ENCRYPT 1 aes.h: # de ...

  2. const,static,extern 简介

    const,static,extern 简介 一.const与宏的区别: const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量. 执行时刻:宏是预编 ...

  3. C++中的const

    一,C++中const的基本知识 1.C++中const的基本概念 1.const是定义常量的关键字,表示只读,不可以修改. 2.const在定义常量的时候必须要初始化,否则报错,因为常量无法修改,只 ...

  4. const extern static 终极指南

    const extern static 终极指南 不管是从事哪种语言的开发工作,const extern static 这三个关键字的用法和原理都是我们必须明白的.本文将对此做出非常详细的讲解. co ...

  5. const let,console.log('a',a)跟console.log('a'+a)的区别

    const 创建一个只读的常量 let块级作用域 const let重复赋值都会报错 console.log('a',a) a console.log('a'+a) a2 逗号的值会有空格:用加号的值 ...

  6. es6之let和const

    在javascript中,我们都知道使用var来声明变量.javascript是函数级作用域,函数内可以访问函数外的变量,函数外不能访问函数内的变量. 函数级作用域会导致一些问题就是某些代码块内的变量 ...

  7. construction const parameter问题 构造函数const引用参数问题

    工程在window下编译没有任何问题, 但是在linux(CentOS6)下编译就老是报错 C++ 编译器已升级到最新版 6.1.0 错误如下: In file included /bits/stl_ ...

  8. Error:const char* 类型的实参和LPCWSTR类型的形参不兼容的解决方法。

    在C++的Windows 应用程序中经常碰到这种情况. 解决方法: 加入如下转换函数: LPCWSTR stringToLPCWSTR(std::string orig) { size_t origs ...

  9. C#基础知识七之const和readonly关键字

    前言 不知道大家对const和readonly关键字两者的区别了解多少,如果你也不是很清楚的话,那就一起来探讨吧!探讨之前我们先来了解静态常量和动态常量. 静态常量 所谓静态常量就是在编译期间会对变量 ...

  10. const 与 readonly知多少

    原文地址: http://www.cnblogs.com/royenhome/archive/2010/05/22/1741592.html 尽管你写了很多年的C#的代码,但是可能当别人问到你cons ...

随机推荐

  1. SpringMVC02——第一个MVC程序-注解版(high版!!!!)

    注解版 新建一个子项目,添加Web支持 在pom.xml文件中引入相关的依赖:主要引入Spring框架核心库.SpringMVC.servlet,JSTL等. 创建实体类Fruit package c ...

  2. 百度网盘(百度云)SVIP超级会员共享账号每日更新(2023.11.22)

    一.百度网盘SVIP超级会员共享账号 可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答. 我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免 ...

  3. [转帖]TLS1.3 正式版发布 — 特性与开启方式科普

    https://cloud.tencent.com/developer/article/1376033 互联网工程指导委员会(IETF)释出了传输层安全性协议的最新版本 TLS 1.3.TLS 被广泛 ...

  4. [转帖]Linux 性能监控 Sar (Sysstat) 示例

    https://bbs.huaweicloud.com/blogs/345343#   [摘要] 使用 sar,您可以实时监控各种 Linux 子系统(CPU.内存.I/O..)的性能,还可以持续收集 ...

  5. [转帖]django使用html渲染页面样式+数据库管理员的创建

    一.django页面渲染 1.在templates中创建html格式的文件-index.html,在该文件中添加body,设置样式,比如: <h1 style = "backgroun ...

  6. 各种数据库shell一键登录的方法

    各种数据库shell一键登录的方法 一个小场景 想通过shell 直接执行一些内容. 然后发现通过shell就可以. 所以这里总结一下 1. Oracle export ORACLE_HOME=/u0 ...

  7. [转帖]TiDB 数据库的调度

    https://docs.pingcap.com/zh/tidb/stable/tidb-scheduling#%E4%BF%A1%E6%81%AF%E6%94%B6%E9%9B%86 PD (Pla ...

  8. [转帖]AlertManager 配置邮箱告警

    http://www.mydlq.club/article/126/ 2022-12-02 13:17:00KUBERNETESPROMETHEUSALERTMANAGER 文章目录 一.邮箱告警说明 ...

  9. Jmeter学习之一_连接与测试Redis

    Jmeter学习之一_连接与测试Redis 简介 下载: https://dlcdn.apache.org//jmeter/binaries/apache-jmeter-5.6.zip 注意事项: D ...

  10. [转帖]【JVM】GC算法与垃圾收集器

    引入 java 语言中一个显著的特点就是引入了java回收机制,是c++程序员最头疼的内存管理的问题迎刃而解,它使得java程序员在编写程序的时候不在考虑内存管理.由于有个垃圾回收机制,可以有效的防止 ...