ES 6 系列 - 变量声明
let 和 const
let 声明
(一)基本用法
let 声明的变量只在块级作用域内有效,出了该块则报错,最常见且适合的地方在 for 循环中:
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
上面的 i 通过 var 方式声明,(循环次数内)全局有效且只有一个,故每次循环结束后, i 的值会被更新,从而导致在完成所有循环后, a 数组中所有的成员中的 i 均指向最后一次更新的值, 即 10,而使用 let 声明:
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
在每次循环时,该次循环体(代码块)中的 i 只对当前代码块有效,简单而言即:每次循环的 i 相当于一个新的变量,故最终结果是 6 。
(二)var 的变量提升
先看一个例子:
console.log(foo); // 输出undefined
var foo = 2;
按照正常的逻辑,执行 console 时,变量 foo 在内存中并不存在,但是此时会输出 undefined(未赋值) 错误,这就是 var 声明的变量提升:脚本运行时,变量已经存在,但是没有值,最终输出 undefined。使用 let 声明可以避免变量提升。
(三)暂时性死区
只要块级作用域内存在 let 指令,它所声明的变量就 “绑定” 在这个区域,不在受外部影响。
if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError let tmp; // TDZ结束
console.log(tmp); // undefined tmp = 123;
console.log(tmp); // 123
}
如上例所示,在 let 命令之前, tmp 变量都不可用, 这块区域都属于 tmp 的 “死区”,语法上称这种现象为 “暂时性死区”。
注意:1.使用 let 命令时,typeof 不在是一个百分百安全操作;
2.一个比较隐蔽的死区:
function bar(x = y, y = 2) {
return [x, y];
} bar(); // 报错
调用 bar() 报错的原因在于 x = y 时,y 并没有声明,属于 “死区”,故报错。解决办法是将函数中参数位置对调即可。
同理:
// 不报错
var x = x; // 报错
let x = x;
// ReferenceError: x is not defined
总之:暂时性锁区的本质是,只要一进入当前作用域,所要使用的变量就已经存在,但是处于不可获取的状态,只有等到声明语句出现,才可以获取和使用。
(四)块级作用域
es 5 只有全局和函数作用域两种,接下来看两个 es5 的例子:
1.内层变量覆盖外层变量
var tmp = new Date(); function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
} f(); // undefined
在 fun f() 中,因为存在 var 指令,故可以说在 f() 中就会存在变量提升的现象(而且优先级貌似蛮高的), 所以这就会导致 console undefined 错误,而不是 console 时间;
2.用来计数的循环变量泄露成全局变量:
var s = 'hello'; for (var i = 0; i < s.length; i++) {
console.log(s[i]);
} console.log(i); // 5
上例可以看出,在循环结束后,作为控制循环的 i 变量并没有消失,这样就很容易泄露,可能会被恶意利用。
而 let 的使用为 es 6 新増了块级作用域。
const 声明
效果跟 java 中的 static final 差不多;
需要注意:
1.const 的变量声明时必须赋值,否则报错;
2.const 的变量一旦声明,其值只读,不可改变;
3.const 的作用域与 let 相同: 只在声明所在的块级作用域内有效;
4.const 的变量不存在变量提升现象,同样存在暂时性死区;
5.const 的变量,不可重复声明;
6.关于引用类型的对象,一个例子:
const a = [];
a.push('Hello'); // 可执行
a.length = 0; // 可执行
a = ['Dave']; // 报错
常量 a 中存储了一个数组对象的地址,然后这个数组对象中的内容是可变的,但是,最后一行很明显是把一个新的数组对象的地址赋值给 a,这就导致了报错。
ES 6 系列 - 变量声明的更多相关文章
- es6 快速入门 系列 —— 变量声明:let和const
其他章节请看: es6 快速入门 系列 变量声明:let和const 试图解决的问题 经典的 var 声明让人迷惑 function demo1(v){ if(v){ var color='red' ...
- es6系列-变量声明
es6系列所有文章都是阅读阮一峰老师的<ES6标准入门>(第2版)所做的读书笔记.方便日后查阅相关基础知识. git地址: https://github.com/rainnaZR/es6- ...
- Nodejs与ES6系列1:变量声明
1.声明变量 在JS当中一个变量的作用域(scope)是程序中定义这个变量的区域.变量分为两类,全局(global)的和局部的.其中全局变量的作用域是全局性的,即在JavaScript代码中,它处处都 ...
- ES6系列之变量声明let const
ES6也出来好久了,最近闲来无事就想着吧es6做一个系统的总结,巩固自己的知识,丰富一下博客. 为什么叫ES6 实际上是ECMA的一个打的标准,这个标准是在2015年6月发布的,正式的名字实际是es2 ...
- 详解变量声明加 var 和不加 var 的区别
在全局作用域中声明变量加 var 关键字和不加 var ,js 引擎都会将这个变量声明为全局变量,在实际运行时,两种声明方式的变量的行为也是几乎一致的.但是在全局作用域下是否声明一个变量的 时候加va ...
- ES 6 系列 - 赋值的新方式:解构赋值
变量的解构赋值 es 6 允许按照一定的模式,从数组和对象中提取值,然后对变量进行赋值,这被称之为解构: 一.数组的解构赋值 最基本写法: let [a, b, c] = [1, 2, 3]; a / ...
- Js 变量声明提升和函数声明提升
Js代码分为两个阶段:编译阶段和执行阶段 Js代码的编译阶段会找到所有的声明,并用合适的作用域将它们关联起来,这是词法作用域的核心内容 包括变量声明(var a)和函数声明(function a(){ ...
- js 碎片整理(变量声明,函数作用域)
1.变量声明: 在非严格模式下,函数可以对未声明的变量赋值,而这样赋值的结果就是该变量就会变成全局变量. (function(){ var a = 1; })(); console.log(a) ; ...
- TypeScript 素描-变量声明
博文读自 TypeScript 官方文档而来,不具有学习性,仅是本人学习时记录以供日后翻阅 ,有学习TypeScript的朋友还请去看更为详细的官方文档 /* 变量声明在之前的js中一直是使用var关 ...
随机推荐
- 禁止 gVim 在 Linux 下自动生成 undo 文件 *.un~
在配置文件 .vimrc 中加入配置项, set noundofile 完.
- Spring Security(十四):5.4 Authorize Requests
Our examples have only required users to be authenticated and have done so for every URL in our appl ...
- 从Linux内核角度看中间人攻击(ARP欺骗)并利用Python scapy实现
邻居子系统与ARP协议 邻居子系统的作用就是将IP地址,转换为MAC地址,类似操作系统中的MMU(内存管理单元),将虚拟地址,转换为物理地址. 其中邻居子系统相当于地址解析协议(IPv4的ARP协议, ...
- LNMP环境
准备工作:1)把所有的软件安装在/usr/local/,源码包放在/package/,数据:自定义,日志文件:自定义 创建www所属组及用户/usr/sbin/groupadd www/usr/sbi ...
- SQL开发规范
一.SQL代码规范: 1.头部 --************************************************************************** --所属主题: ...
- Android so注入(inject)和Hook技术学习(三)——Got表hook之导出表hook
前文介绍了导入表hook,现在来说下导出表的hook.导出表的hook的流程如下.1.获取动态库基值 void* get_module_base(pid_t pid, const char* modu ...
- Java线程池实现原理与技术(ThreadPoolExecutor、Executors)
本文将通过实现一个简易的线程池理解线程池的原理,以及介绍JDK中自带的线程池ThreadPoolExecutor和Executor框架. 1.无限制线程的缺陷 多线程的软件设计方法确实可以最大限度地发 ...
- .net core实践系列之SSO-同域实现
前言 SSO的系列还是以.Net Core作为实践例子与大家分享,SSO在Web方面复杂度分同域与跨域.本篇先分享同域的设计与实现,跨域将在下篇与大家分享. 如有需要调试demo的,可把SSO项目部署 ...
- Item 21: 比起直接使用new优先使用std::make_unique和std::make_shared
本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 让我们先从std::make_unique和std::make_s ...
- python之psutil模块详解(Linux)--小白博客
Python-psutil模块 windows系统监控实例,查询 https://www.cnblogs.com/zhou2019/p/10567282.html 1.简单介绍 psutil是一个跨平 ...