《关于ES6的学习》
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的学习》的更多相关文章
- 简单物联网:外网访问内网路由器下树莓派Flask服务器
最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...
- 利用ssh反向代理以及autossh实现从外网连接内网服务器
前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...
- 外网访问内网Docker容器
外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...
- 外网访问内网SpringBoot
外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...
- 外网访问内网Elasticsearch WEB
外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...
- 怎样从外网访问内网Rails
外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...
- 怎样从外网访问内网Memcached数据库
外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...
- 怎样从外网访问内网CouchDB数据库
外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...
- 怎样从外网访问内网DB2数据库
外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...
- 怎样从外网访问内网OpenLDAP数据库
外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...
随机推荐
- vue.js 项目打包
vuejs是个前端框架,npm run dev的目的在于前端开发的时候可以实时调试.所以npm run dev 只是开发时期会用到,在生产环境中我们应该使用nginx,apahce tomcat等应用 ...
- [转]关于浏览器css选择器性能优化
作为一个前端开发, 我觉得很有必要了解浏览器对css选择器的解析,因为这个关系到页面的渲染,高效的方式.避开开销大的方式这些无疑为网站加载缩短了时间. 最近在新的项目中陷入了一个误区,也是出于对jqu ...
- VMware与Hyper-V
前段时间在Windows10上安装Hyper-V,使用docker时,提示要卸载VMware 今天重新安装VMware时,提示: 根据连接进去:https://kb.vmware.com/s/arti ...
- linux erlang环境安装
1.安装环境:yum -y install make gcc gcc-c++ kernel-devel m4 glibc-devel autoconfyum -y install ncurses-de ...
- ES6-let & const
let和const命令 let 它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效. for(let i = 0; i < arr.length; i++){} 用let命 ...
- Python 中单双引号
TODO, 在python中, 其实单双引号还是有分别的, 具体是什么?
- android 常用adb 及linux 命令
一.ADB相关 adb shell:进入连接的USB调试模式设备shell命令行下 adb tcpip 5555:将USB连接的调试及的连接方式改为网络远程模式进行调试 这里端口为5555(adb 默 ...
- Linux strace命令详解
Linux抓取TCP的命令: tcpdump ps -ef 参数命令详解: Linux下一切皆文件,我们打开一个socket,实际上也是打开了一个文件 我们打开一个网卡,实际上也是调用Linux系统的 ...
- Linux 系统磁盘挂载信息文件
设置文件系统挂载信息的文件(etc/fstab),使得开机能够自动挂载磁盘分区 文件系统挂载 方法一: 直接挂在,临时生效 # 格式化系统(没有格式化就没有文件系统,放不了数据) dd if=/dev ...
- RedHat 7 安装PostgreSQL 10.5
系统环境 Redhat: Version: 7.4.1708 Architecture: x86_64 Address: 10.127.1.11 User: root Uassword: redhat ...