var

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

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

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

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

function test() {
var a
//a声明没有赋值
console.log('1: ', a) //undefined
if (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 defined function test() {
if(true) {
let a = 1
}
console.log(a)
}
test() // a is not defined

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

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

const

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

const type = "ACTION"

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


const type = "ACTION"
type = 1
console.log(type) //"type" is read-only const 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) {
//这块区域是TDZ
let 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无法污染外部函数

在全局作用域声明

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

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

最佳实践

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

《关于ES6的学习》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. Oracle中的锁

    Oracle中的锁 锁是一种机制,多个事务同时访问一个数据库对象时,该机制可以实现对并发的控制 按照用户系统锁可以分为自动锁和显示锁. 自动锁(系统上锁):DML锁.DDL锁.systemlocks锁 ...

  2. 微信网页授权获取code

    <script> var code = GetQueryString('code'); var callback = 'personal.html'; var appId = " ...

  3. Python中操作HTTP请求的urllib模块详解

    urllib 是 Python 标准库中用于网络请求的库.该库有四个模块,分别是urllib.request,urllib.error,urllib.parse,urllib.robotparser. ...

  4. BZOJ2227 [Zjoi2011]看电影(movie)

    Description \(k\)个座位,\(n\)个人依次过来,每人随机从\(k\)个座位中选择一个,并从它开始不停向后走直到遇到空座位坐下.求所有人都能坐下的概率(即没有人走到第\(k+1\)个位 ...

  5. 详解php 获取文件名basename()函数的用法

    PHP 中basename()函数给出一个包含有指向一个文件的全路径的字符串,此函数返回基本的文件名,本篇文章收集了关于使用PHP basename()函数获取文件名的几篇文章,希望对大家理解使用PH ...

  6. ARCGIS知乎上的好文章

    http://zhihu.esrichina.com.cn/?/feature/ArcGISAndroidDevNote ArcGIS知乎上有哪些干货可以推荐? http://zhihu.esrich ...

  7. reentrantlock用于替代synchronized

    1.①使用reentrantlock可以完成同样的功能   ②需要注意的是,必须要必须要必须要手动释放锁(重要的事情说三遍)   ③使用syn锁定的话如果遇到异常,jvm会自动释放锁,但是lock必须 ...

  8. oracle 手动打jar 包

    1.到loracle 的安装目录,D:\ProgramFiles\oracle\product\11.2.0\dbhome_1\jdbc\lib,找到文件 ojdbc6.jar,复制到 D 盘. 2. ...

  9. js 和springboot内存图

  10. 基于 Docker 的现代软件供应链

    [编者按]本文作者为 Marc Holmes,主要介绍一项关于现代软件供应链的调查结果.本文系国内 ITOM 管理平台 OneAPM 编译呈现,以下为正文. 3 月初,为了了解软件供应链的现状以及 D ...