本章涉及3个知识点,var、let、const,现在让我们了解3个关键字的特性和使用方法。

var

JavaScript中,我们通常说的作用域是函数作用域,使用var声明的变量,无论是在代码的哪个地方声明的,都会提升到当前作用域的最顶部,这种行为叫做变量提升(Hoisting)

也就是说,如果在函数内部声明的变量,都会被提升到该函数开头,而在全局声明的变量,就会提升到全局作用域的顶部。

function test() {console.log('1: ', a) //undefinedif (false) {var a = 1}console.log('3: ', a) //undefined
}test()

实际执行时,上面的代码中的变量a会提升到函数顶部声明,即使if语句的条件是false,也一样不影响a变量提升。

function test() {var a//a声明没有赋值console.log('1: ', a) //undefinedif (false) {a = 1}//a声明没有赋值console.log('3: ', a) //undefined
}

在函数嵌套函数的场景下,变量只会提升到最近的一个函数顶部,而不会。

//b提升到函数a顶部,但不会提升到函数test。
function test() {function a() {if (false) {var b = 2}}console.log('b: ', b)
}test() //b is not defined

如果a没有声明,那么就会报错,没有声明和声明后没有赋值是不一样的,这点一定要区分开,有助于我们找bug。

//a没有声明的情况
a is not defined

let

let和const都能够声明块级作用域,用法和var是类似的,let的特点是不会变量提升,而是被锁在当前块中。

一个非常简单的例子:

function test() {if(true) {console.log(a)//TDZ,俗称临时死区,用来描述变量不提升的现象let a = 1}
}
test()  // a is not definedfunction test() {if(true) {let a = 1}console.log(a)
}
test() // a is not defined

唯一正确的使用方法:先声明,再访问。

function test() {if(true) {let a = 1console.log(a)}
}
test() // 1

const

声明常量,一旦声明,不可更改,而且常量必须初始化赋值。

const type = "ACTION"

我们试试重新声明type,看看会报什么错:


const type = "ACTION"
type = 1
console.log(type) //"type" is read-onlyconst type = "ACTION"
let type = 1
console.log(type) //Duplicate declaration "type"

const虽然是常量,不允许修改默认赋值,但如果定义的是对象Object,那么可以修改对象内部的属性值。

const type = {a: 1
}
type.a = 2 //没有直接修改type的值,而是修改type.a的属性值,这是允许的。
console.log(type) // {a: 2}

const和let的异同点

相同点:const和let都是在当前块内有效,执行到块外会被销毁,也不存在变量提升(TDZ),不能重复声明。

不同点:const不能再赋值,let声明的变量可以重复赋值。

临时死区(TDZ)

上面我们也提到了TDZ的场景,那么,有什么用呢?答案就是没什么用。

临时死区的意思是在当前作用域的块内,在声明变量前的区域叫做临时死区。


if (true) {//这块区域是TDZlet a = 1
}

块级作用域的使用场景

除了上面提到的常用声明方式,我们还可以在循环中使用,最出名的一道面试题:循环中定时器闭包的考题

在for循环中使用var声明的循环变量,会跳出循环体污染当前的函数。

for(var i = 0; i < 5; i++) {setTimeout(() => {console.log(i) //5, 5, 5, 5, 5}, 0)
}
console.log(i) //5 i跳出循环体污染外部函数//将var改成let之后
for(let i = 0; i < 5; i++) {setTimeout(() => {console.log(i) // 0,1,2,3,4}, 0)
}
console.log(i)//i is not defined i无法污染外部函数

关于这个使用场景的具体分析可以查看我写的另外一篇文章:JavaScript同步、异步、回调执行顺序之经典闭包setTimeout面试题分析

在全局作用域声明

如果在全局作用域使用let或者const声明,当声明的变量本身就是全局属性,比如closed。只会覆盖该全局变量,而不会替换它。

window.closed = false
let closed = trueclosed // true
window.closed // false

最佳实践

在实际开发中,我们选择使用var、let还是const,取决于我们的变量是不是需要更新,通常我们希望变量保证不被恶意修改,而使用大量的const,在react中,props传递的对象是不可更改的,所以使用const声明,声明一个对象的时候,也推荐使用const,当你需要修改声明的变量值时,使用let,var能用的场景都可以使用let替代。

=> 返回文章目录

《深入理解ES6》笔记——块级作用域绑定(1)相关推荐

  1. ES6中块级作用域下的函数声明

    背景 因为ES5的时候没有块级作用域,所以ES5规定不能再if这样的块中声明函数,但是为了兼容各大浏览器并没有严格遵守这条规定. ES6的时候引入了块级作用域,规定在块级作用域中声明函数就相当于使用l ...

  2. [ES6] 细化ES6之 -- 块级作用域

    所谓的块级作用域,可能是一个{},一个代码块,一句话 let关键字 let 与 var 区别 区别 var let 变量提升 有 无 作用域 全局作用域.函数作用域 全局作用域.函数作用域和块级作用域 ...

  3. ES6_1.块级作用域绑定_临时死区TDZ

    临时死区 JavaScript引擎在扫描代码发现变量声明时,要么将它们提升至作用域顶部(var声明),要么将声明放到TDZ中(let.const).访问TDZ中的变量会触发运行时错误.只有执行过变量声 ...

  4. ES6基础2(块级作用域、数组对象解构)-学习笔记

    文章目录 ES6基础2(块级作用域.数组对象解构)-学习笔记 块级作用域 数组解构 对象解构 字符串解构 函数的参数解构 ES6基础2(块级作用域.数组对象解构)-学习笔记 块级作用域 //let c ...

  5. 搭建Babel运行环境,Traceur ES6模板,块级作用域,let和const命令

    搭建Babel运行环境 Babel(http://babeljs.io/)可用于将使用ES6语法的脚本转化为ES5语法的脚本,基本功能的安装步骤如下: 1.安装node解释器和npm包管理工具 2.安 ...

  6. es6 ie不兼容 函数_ES6:什么是块级作用域?

    在 ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景. 我们先来看一下下面这种情况:内层变量可能会覆盖外层变量. var txt = '外层变量-->你好呀';func ...

  7. ES6 块级作用域详解

    什么是块级作用域 ES6 中新增了块级作用域.块作用域由 { } 包括,if 语句和 for 语句里面的 { } 也属于块作用域. 为什么需要块级作用域 第一种场景:内部变量会覆盖外部变量 var t ...

  8. java区块作用域_ES6-let、const和块级作用域

    1.介绍 总的来说,ES6是在ES2015的基础上改变了一些书写方式,开放了更多API,这样做的目的最终还是为了贴合实际开发的需要.如果说一门编程语言的诞生是天才的构思和实现,那它的发展无疑就是不断填 ...

  9. javascript中作用域、全局作用域、局部作用域、隐式全局变量、块级作用域、作用域链、预解析

    作用域 作用域指的是代码的作用范围,按照作用域划分变量可分为全局变量和局部变量:作用域可分为: 全局作用域: 指全局变量作用的范围:全局变量指的是通过var在函数外面声明的变量,在js中任何位置都可以 ...

最新文章

  1. 在NVIDIA A100 GPU上利用硬件JPEG解码器和NVIDIA nvJPEG库
  2. 史上最简洁的UITableView Sections 展示包含NSDicionary 的NSArray
  3. nodejs中服务器返回响应信息中的中文乱码
  4. 如何针对产品销售设计一套有效的奖励和惩罚销售措施?
  5. JZOJ 5898. 【NOIP2018模拟10.6】距离统计
  6. redis在windows10上跑起来
  7. 光端机怎样使用?光端机怎么和交换机连接?
  8. [Leedcode][JAVA][第128题][最长连续序列][Hash]
  9. Android 音频开发(二) 采集一帧音频数据
  10. cdr怎样把一张图片随意变形_如何设计一张趣味的海报?
  11. 你需要知道的包管理器(Package Manager)
  12. Python之迭代器(iterator)
  13. 《数据挖掘概念与技术》第三版 范明 孟小峰译 课后习题答案(二)
  14. C语言——链表简单介绍
  15. C++之个人银行账户管理程序(二)
  16. 备战蓝桥杯—2014(4)史丰收速算
  17. 2 年前端面试心路历程(字节跳动、YY、虎牙、BIGO)
  18. php zend_extension,extension 和zend_extension 两种扩展
  19. 转录组入门(2):读文章拿到测序数据
  20. 保险行业的“偿二代”

热门文章

  1. MTU(最大传输单元)
  2. 风清杨之Oracle的安装与说明
  3. 轻松解决Windows7声卡驱动不全问题
  4. 仿FLASH动感十足鼠标滑过放大的菜单代码
  5. ISA Server 2006 的内部客户端概念
  6. C#之Action和Func的用法(转自 https://www.cnblogs.com/LipeiNet/p/4694225.html)
  7. 一道有关球赛队员分配的C++程序题目
  8. 数据库启动时报ORA-00845错误解决方法
  9. xtraTabbedMdiManager 双击最大化和关闭后返回主界面 z
  10. Linux 下的终端选择,以及剪切板配置