ES6系列之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
})(); // es6
(function(){
if(false) {
let temp = 1;
}
console.log(temp); // Uncaught ReferenceError: temp is not defined
})();从代码中我们可以很清晰看到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 definedOK,问题解决了,仅仅是将’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
})(); (function() {
if(true) {
let temp = 1;
var temp = 2; // Uncaught SyntaxError: Identifier 'temp' has already been declared
}
})(); (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);
});
} // 伪代码
var fnArr;
fnArr = [];
{
var i;
i = 0; if(i < 3) {
fnArr.push(function() {
console.log(i);
})
}
i++;
if(i < 3) {
fnArr.push(function() {
console.log(i);
});
}
i++;
...
}
这里可惜清晰得看到所有的i都是一个i。。。那使用了let以后呢?
var fnArr = [];
for(let i = 0; i < 3; i++) {
fnArr.push(function() {
console.log(i);
});
} // 伪代码
var fnArr;
fnArr = [];
{
let i;
i = 0; if(i < 3) {
let i = i;
fnArr.push(function() {
console.log(i);
})
}
i++;
if(i < 3) {
let i = i;
fnArr.push(function() {
console.log(i);
});
}
i++;
...
}
是不是看出点名堂?其实我们完全可以这样理解,在每一次循环中都重新声明了i,并且被赋值为外层i的当前值。(注意啊,这里只是伪代码,便于理解,实际中let i = i是会抛出异常的)
ES6系列之let/const及块级作用域的更多相关文章
- 开始学习es6(二) let 与 const 及 块级作用域
1.var JavaScript中,我们通常说的作用域是函数作用域,使用var声明的变量,无论是在代码的哪个地方声明的,都会提升到当前作用域的最顶部,这种行为叫做变量提升(Hoisting) cons ...
- ES6的 let const 以及块级作用域
let声明变量 用法类似于var,但是所声明的变量只在let所在的代码块内有效. 1 . 在ES6环境下,let声明的变量不能在声明之前调用. 例: console.log(i); //会报错,这叫做 ...
- ES6标准入门 第二章:块级作用域 以及 let和const命令
一.块级作用域 1.为什么需要块级作用域? ES5中只有全局作用域和函数作用域,带来很多不合理的场景. (1)内层变量可能会覆盖外层变量: var tem = new Date(); function ...
- let/const及块级作用域
本系列是在平时阅读.学习.实际项目中有关于es6中的新特性.用发的简单总结,目的是记录以备日后温习:本系列预计包含let/const.箭头函数.解构.常用新增方法.Symbol.Set&Map ...
- ES6-let、const和块级作用域
1.介绍 总的来说,ES6是在ES2015的基础上改变了一些书写方式,开放了更多API,这样做的目的最终还是为了贴合实际开发的需要.如果说一门编程语言的诞生是天才的构思和实现,那它的发展无疑就是不断填 ...
- ES6学习笔记(1)- 块级作用域
1. var声明变量和变量提升(Hoisting)机制的问题 在JS中通过var关键字声明的变量,无论在函数作用域中亦或是全局作用域中,都会被当成当前作用域顶部的变量,和就是所谓的提升机制(Hoist ...
- ES6入门一:块级作用域(let&const)、spread展开、rest收集
let声明 const声明 块级作用域 spread/rest 一.let声明与块作用域 在ES6之前,JavaScript中的作用域基本单元就是function.现在有了let就可以创建任意块的声明 ...
- ES6 - Note1:块级作用域与常量
在ES6以前,ES不支持块级作用域,只有全局作用域和函数作用域,所有变量的声明都存在变量声明提升. 1.let 关键字 声明一个块级变量,只在一个代码块中有效,如果在块外面访问便会报错,如下所示: { ...
- javascript之模拟块级作用域
在java.C++等语言中,变量i在会在for循环的语句块中定义,循环一旦结束,变量i就会被销毁.可是在javaScript中,从定义开始,就可以在函数内部随处访问.比如 function outpu ...
随机推荐
- 【Java】关于项目启动大请求量高负载时如何确保db等资源不出错的问题
如果一个项目启动时(单机), 瞬间来了1000个访问, 如何确保db等资源不会压垮呢? 现在想想我当时回答的并不好, 而现在看公司框架才发现其实有针对于这一块做过专门的优化的.下面就来分享下公司关 ...
- linux下磁盘管理(du、df)命令使用
DF :disk free 磁盘可用量 DU: disk usage 磁盘使用 df:列出文件系统的整体磁盘使用量: df参数: -a:列出所有的文件系统,包括系统特有的/proc等文件系统 -k:以 ...
- flume实现kafka到hdfs测试用例
kafka 到hdfs at1.sources =st1 at1.channels = ct1 at1.sinks = kt1 # For each one of the sources, the t ...
- jsp的四个作用域page、request、session、application
1.简单说 page指当前页面.在一个jsp页面里有效 2.request 指从http请求到服务器处理结束,返回响应的整个过程.在这个过程中使用forward方式跳转多个jsp.在这些页面里你都可以 ...
- .net core+Spring Cloud学习之路 二
前言: 原本计划这次写一下搭建eureka群集.但是发现上次写的只是服务的注册,忘了写服务的发现,所以这次先把服务发现补上去. 我们基于上篇文章,再新建两个.net core web api项目,分别 ...
- 653. Two Sum IV - Input is a BST-easy
我不懂有没有收藏之类的功能,收藏别人的解法. tql,不懂为什么直接比较set里的值,不是两个数sum么 有一些答案都用到了iterator迭代器 http://www.cplusplus.com/r ...
- Appium环境搭建——安卓真机调试注意点
1.安卓设备连接失败 通过adb devices命令 查看安卓设备的连接情况,如图,未成功连接 解决方法: (1)关闭360安全卫士和360手机助手(2)查看5037端口是否被占用 netstat - ...
- java--遇到NoSuchMethodError通用解决思路
https://www.cnblogs.com/xiaoMzjm/p/4566672.html 最近接手新项目,项目一跑,NoSuchMethodError蹦出来了,好不容易解决了,换一个电脑,NoS ...
- ScreenPresso注册码
[3]-[screenpressopro]-[5705]-[www.dayanzai.me]-[01/26/2016]-[Zkj8i42HhuCW1UCNtaklHv7Eekr1Wkt4wKHFket ...
- android开发解决Error:Execution failed for task ':app:transformDexArchiveWithExternalLibsDexMergerForDebug'. > java.lang.RuntimeException: java.lang.RuntimeException: c.....
网上常见的方法我都试过,都没能解决,偶然看到的一个方法解决了,在这了记录一下. 在App目录下的build.gradle的android{ ... ....}中添加如下代码,即可解决.(xx.xx. ...