let/const及块级作用域
本系列是在平时阅读、学习、实际项目中有关于es6中的新特性、用发的简单总结,目的是记录以备日后温习;本系列预计包含let/const、箭头函数、解构、常用新增方法、Symbol、Set&Map、Proxy、reflect、Class、Module、Iterator、Promise、Generator、async/await
let/const为我们带来了什么?
let
- 约束变量提升
(function foo() {
console.log(a);
let a = 1;
})(); // Uncaught ReferenceError: a is not defined总结下来就是一句: 在变量使用之前,必须先要声明,变量声明永远在使用之前。
- 带来了块级作用域

// es5
(function(){
if(false) {
var temp = 1;
}
console.log(temp); // undefined
})();</span><span style="color: #008000;">//</span><span style="color: #008000;"> es6</span>
(<span style="color: #0000ff;">function</span><span style="color: #000000;">(){
</span><span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">false</span><span style="color: #000000;">) {
let temp </span>= 1<span style="color: #000000;">;
}
console.log(temp); </span><span style="color: #008000;">//</span><span style="color: #008000;"> Uncaught ReferenceError: temp is not defined</span>
})();</pre>

从代码中我们可以很清晰看到es6的let的块级作用域,那么块级作用域有什么应用呢?举个例子:

var fnArr = [];
for(var i = 0; i < 5; i++) {
fnArr.push(function() {
console.log(i);
});
}
fnArr[0](); //
fnArr[1](); //
fnArr[2](); //
fnArr[3](); //
fnArr[4](); //
console.log(i); //
如果没有仔细分析,执行的结果是不是有些出乎意料呢? 是的,我们本意在for循环内部使用的变量i被泄露成了全局变量,而且在for循环的每一次循环,变量i并没有被重新声明,实际上数组fnArr中保存的每一个函数中引用的都是同一个变量i,所以才导致了现在的结果,那怎么让代码按照我们最初的想法运行呢?来看es5中常用的解法

var fnArr1 = [];
for(var i = 0; i < 5; i++) {
(function(j) {
fnArr1.push(function() {
console.log(j);
});
})(i)
}
fnArr1[0](); //
fnArr1[1](); //
fnArr1[2](); //
fnArr1[3](); //
fnArr1[4](); //
console.log(i); //
看起来是解决了,这里实际上用到了闭包的方法,fnArr1中每一项函数引用的j都是当前循环时i的一个副本,这样就解决了前面的问题,但是还有一个问题: 变量i仍然隐式得泄露到了全局

var fnArr1 = [];
for(let i = 0; i < 5; i++) {
fnArr1.push(function() {
console.log(i);
});
}
fnArr1[0](); //
fnArr1[1](); //
fnArr1[2](); //
fnArr1[3](); //
fnArr1[4](); //
console.log(i); // Uncaught ReferenceError: i is not defined
OK,问题解决了,仅仅是将’var‘替换成了let,这就是let带来的便利。
- 产生暂时性死区&禁止重复声明

// 什么是禁止重复声明呢? 先不给书面解释,来看一个es5中经常的写法
(function() {
var temp = 1;
var temp = 2;
var temp = function() {
return 1;
};
})();
上面这段代码执行没有任何问题,最终temp被赋值为一个函数

(function() {
let temp = 1;
var temp = 2; // Uncaught SyntaxError: Identifier 'temp' has already been declared
var temp = function() {
return 1;
};
})();
在第三行时就抛出了一个错误:temp已经被声明,是的,let声明过的变量,是不允许再次被声明的,再给几个例子巩固一下:

(function() {
var temp = 2;
var temp = function() {
return 1;
};
let temp = 1; // Uncaught SyntaxError: Identifier 'temp' has already been declared
})();(</span><span style="color: #0000ff;">function</span><span style="color: #000000;">() {
</span><span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">true</span><span style="color: #000000;">) {
let temp </span>= 1<span style="color: #000000;">;
</span><span style="color: #0000ff;">var</span> temp = 2; <span style="color: #008000;">//</span><span style="color: #008000;"> Uncaught SyntaxError: Identifier 'temp' has already been declared</span>
}
})();(function() {
if(true) {
let temp = 1;
function temp() { // Uncaught SyntaxError: Identifier 'temp' has already been declared
return 1;
}
}
})();
看出来了吗?只要是在let声明所在的作用域,就不允许再次声明同名变量(包括函数声明)
var foo = 1;
if(true) {
foo = 2; // Uncaught ReferenceError: foo is not defined
let foo;
}看到let的’霸道‘了吧?只要在let所在的作用域,同名的变量就会被let占有,不允许重复声明,同时也要遵守let的规则
- 全局变量不再作为window对象的属性
var foo = 1;
(function() {
bar = 2;
})();
window.foo; //
window.bar; //是的,es5中,全局变量(包括意外泄露的)都将自动被添加为window对象的属性
let foo = 1; window.foo; // undefined
一切尽在不言中。。。
const
- let所拥有的特性,const都有,同时const还有一条:const声明的变量必须进行初始化,并且不能再被重新赋值
const temp = 1;
temp = 2; // Uncaught TypeError: Assignment to constant variable.注意是不能被重新赋值,这样是比较准确的,其实const声明的变量是可以被修改的,当const声明的变量被初始化为复杂数据类型时,const声明的变量就是可变的,至于为什么,自己理解喽(变量标识符中保存的只是复杂数据类型内存地址而已。。。)
const temp = {};
temp.foo = 'aa'; // 这里没问题
temp = {foo: 'aa'}; // 这里就会抛出异常
for循环中的变量声明
前面在记录let块级作用域的时候,我们使用了一个for循环的例子,这里我们不妨试着解析一下for循环的执行过程

var fnArr = [];
for(var i = 0; i < 3; i++) {
fnArr.push(function() {
console.log(i);
});
}</span><span style="color: #008000;">//</span><span style="color: #008000;"> 伪代码</span>
<span style="color: #0000ff;">var</span><span style="color: #000000;"> fnArr;
fnArr </span>=<span style="color: #000000;"> [];
{
</span><span style="color: #0000ff;">var</span><span style="color: #000000;"> i;
i </span>= 0<span style="color: #000000;">; </span><span style="color: #0000ff;">if</span>(i < 3<span style="color: #000000;">) {
fnArr.push(</span><span style="color: #0000ff;">function</span><span style="color: #000000;">() {
console.log(i);
})
}
i</span>++<span style="color: #000000;">;
</span><span style="color: #0000ff;">if</span>(i < 3<span style="color: #000000;">) {
fnArr.push(</span><span style="color: #0000ff;">function</span><span style="color: #000000;">() {
console.log(i);
});
}
i</span>++<span style="color: #000000;">;
...
}</span></pre>
这里可惜清晰得看到所有的i都是一个i。。。那使用了let以后呢?

var fnArr = [];
for(let i = 0; i < 3; i++) {
fnArr.push(function() {
console.log(i);
});
}</span><span style="color: #008000;">//</span><span style="color: #008000;"> 伪代码</span>
<span style="color: #0000ff;">var</span><span style="color: #000000;"> fnArr;
fnArr </span>=<span style="color: #000000;"> [];
{
let i;
i </span>= 0<span style="color: #000000;">; </span><span style="color: #0000ff;">if</span>(i < 3<span style="color: #000000;">) {
let i </span>=<span style="color: #000000;"> i;
fnArr.push(</span><span style="color: #0000ff;">function</span><span style="color: #000000;">() {
console.log(i);
})
}
i</span>++<span style="color: #000000;">;
</span><span style="color: #0000ff;">if</span>(i < 3<span style="color: #000000;">) {
let i </span>=<span style="color: #000000;"> i;
fnArr.push(</span><span style="color: #0000ff;">function</span><span style="color: #000000;">() {
console.log(i);
});
}
i</span>++<span style="color: #000000;">;
...
}</span></pre>
是不是看出点名堂?其实我们完全可以这样理解,在每一次循环中都重新声明了i,并且被赋值为外层i的当前值。(注意啊,这里只是伪代码,便于理解,实际中let i = i是会抛出异常的)
转载来源:https://www.cnblogs.com/innooo/p/10438947.html
let/const及块级作用域的更多相关文章
- ES6的 let const 以及块级作用域
let声明变量 用法类似于var,但是所声明的变量只在let所在的代码块内有效. 1 . 在ES6环境下,let声明的变量不能在声明之前调用. 例: console.log(i); //会报错,这叫做 ...
- ES6系列之let/const及块级作用域
本系列是在平时阅读.学习.实际项目中有关于es6中的新特性.用发的简单总结,目的是记录以备日后温习:本系列预计包含let/const.箭头函数.解构.常用新增方法.Symbol.Set&Map ...
- ES6-let、const和块级作用域
1.介绍 总的来说,ES6是在ES2015的基础上改变了一些书写方式,开放了更多API,这样做的目的最终还是为了贴合实际开发的需要.如果说一门编程语言的诞生是天才的构思和实现,那它的发展无疑就是不断填 ...
- 开始学习es6(二) let 与 const 及 块级作用域
1.var JavaScript中,我们通常说的作用域是函数作用域,使用var声明的变量,无论是在代码的哪个地方声明的,都会提升到当前作用域的最顶部,这种行为叫做变量提升(Hoisting) cons ...
- ES6入门一:块级作用域(let&const)、spread展开、rest收集
let声明 const声明 块级作用域 spread/rest 一.let声明与块作用域 在ES6之前,JavaScript中的作用域基本单元就是function.现在有了let就可以创建任意块的声明 ...
- ES6 浅谈let与const 块级作用域之封闭空间(闭包)
ES6新增了 let const 命令,用来声明变量.它的用法类似于 var ,但是所声明的变量,只在 let const 命令所在的代码块内有效. var const 不允许重复声明 用处: 可 ...
- ES6 let const 声明变量 块级作用域
ES6 中除了使用 var 定义变量,还有let.const,定义变量. function getValue(condition){ console.log(typeof value2); // un ...
- 《浏览器工作原理与实践》<09>块级作用域:var缺陷以及为什么要引入let和const?
在前面我们已经讲解了 JavaScript 中变量提升的相关内容,正是由于 JavaScript 存在变量提升这种特性,从而导致了很多与直觉不符的代码,这也是 JavaScript 的一个重要设计缺陷 ...
- ES6标准入门 第二章:块级作用域 以及 let和const命令
一.块级作用域 1.为什么需要块级作用域? ES5中只有全局作用域和函数作用域,带来很多不合理的场景. (1)内层变量可能会覆盖外层变量: var tem = new Date(); function ...
随机推荐
- vue自定义指令获取焦点及过滤器修改时间
<template id="comp3"> <div id="app"> <model :list="selectedl ...
- 时间戳位数不够13位,通过es6 的padEed补零
if(val.toString().length == 10){ val = val.toString().padEnd(13,"0")*1 //不够十三位放后面补零,超过13位也 ...
- 转义字符\e
Windows 平台下,conio.h 中有许多操作控制台颜色.格式的函数.但是再 Linux 平台下却没有类似的函数.经过在网上的一番搜索,找到了解决此问题的方法——转义字符\e.注意,\e这种写法 ...
- 前端每日实战:86# 视频演示如何用纯 CSS 创作一个方块旋转动画
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/gjgyWm 可交互视频 此视频是可 ...
- [洛谷P2296] NOIP2014 寻找道路
问题描述 在有向图G 中,每条边的长度均为1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 1 .路径上的所有点的出边所指向的点都直接或间接与终点连通. 2 .在满足条 ...
- SpringBoot自定义Jackson配置
为了在SpringBoot工程中集中解决long类型转成json时JS丢失精度问题和统一设置常见日期类型序列化格式,我们可以自定义Jackson配置类,具体如下: import com.fasterx ...
- AI 一体机,满足新时代的新需求
AI 变革带来哪些 IT 的新要求? 深度学习的突破和硬件的突飞猛进,使得人工智能“第n春”焕发蓬勃生机.这是历史上第一次,机器可以在如人脸识别等‘人类’工作上做得比我们人类更好. 人工神经网络有许多 ...
- KindEditor 完全复制word内容
Chrome+IE默认支持粘贴剪切板中的图片,但是我要发布的文章存在word里面,图片多达数十张,我总不能一张一张复制吧?Chrome高版本提供了可以将单张图片转换在BASE64字符串的功能.但是无法 ...
- 退役——halfrot's life in OI
这是一个没有人看的博客里丢了两年的坑,还有很多事应该做,但是我很懒,所以今天把它填了. 前记:和很多人的竞赛生涯一样,一开始我也是奋不顾身,奔月而去,然而身处弱校,没有人引导方向,再加上自己很蒻的主要 ...
- 有关于log4j详解
Log4j记录日志使用方法 一.什么是log4j Log4J是Apache的一个开放源代码的项目.通过使用Log4J,程序员可以控制日志信息输送的目的地,包括控制台,文件,GUI组件和NT事件记录器, ...