var、let和const的区别详解
let 和 const 是 ECMAScript6 新推出的特性,其中 let 是能够替代 var 的“标准”,所以我们探讨 var、let 和 const 的区别,首先应该知道 var 到底有什么不规范的地方,或者是说有什么弊端。
var 的 特性
变量提升
var 是 Javascript 用来定义变量的一个关键字,这是一个简单的变量定义方式
var a = 0;
但是如果我们在定义这个变量之前,查询这个 a 的话,其实是不会报错误的
console.log(a); // undefined
var a = 0;
console.log(a); // 0
虽然它输出了 undefined ,但这并不是我们想要的,我们希望在变量初始化前,是无法访问这个变量的,这虽然是一个约束,但是能让你的程序变得更可捉摸与维护。而 var 之所以能在var a = 0;
前被访问,是因为这一句话在编译的时候其实是按以下的顺序进行的:
var a;
console.log(a); // undefined
a = 0;
console.log(a); // 0
这就是为什么第二行 a 会打印出 undefined 的原因了,这个叫做变量提升,使用 var 初始化变量的时候,在该作用域的开始,会先定义这个变量,再在后面进行赋值(初始化)。所以甚至你可以这么玩儿:
console.log(a); // undefined
a = 0;
console.log(a); // 0
var a;
这样也是可以成功打印的,所以大家看到这应该明白了 var 会对程序眼维护造成的困扰吧? a 明明一路看下来没有看到的,居然依旧正常使用?!!这个时候还需要从该作用域查看到底有没有隐藏的var a;
如果没有的话那还需要去作用域外边寻找。
console.log(a); // undefined
let a = 0;
console.log(a); // 0
var 的作用域
我们再来看一下以下代码
for(var i = 0; i < 5; i++){
var a = 0;
}
console.log(i); // 5
console.log(a); // 0
我们定义在 for 循环块中的变量 i、a 居然在循环外都能被取到,这显然并不规范。
那么这里可以再给大家提一个面试经常也会提到的题目
for (var i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i); // 5 5 5 5 5
}, 300);
}
for (let j = 0; j < 5; j++) {
setTimeout(function () {
console.log(j); // 0 1 2 3 4
}, 300);
}
几乎一模一样的代码,就因为var、let的作用域区别,得到的结果大不一样。对于第一个for循环来说,i在全局范围内都有效,在setTimeout函数中没有找到i的定义,所以在全局里才能找到变量i,在for循环执行完之后,event loop中的,setTimeout中的匿名函数开始执行,这个时候的全局i其实已经是5了,所以全部打印出了5。
而对于第二个for循环来说,let有块级作用域的概念,且值得注意的是for循环头部的let声明有一个特殊的行为,这个行为指出变量在循环过程中不止被声明一次,每次迭代都会被声明。随后的每个迭代都会使用上一个迭代结束时的值来初始化这个变量。这使得我们的j,每次执行其实都是块级作用域中的不同的一个变量,自然就不是最终的5了。
所以如果在不能使用E6的时候,可以使用闭包来创建一个新的作用域。这个闭包能保留对它被声明的位置所处的作用域的引用,将i强行容留在自执行函数的作用域中使其不被回收。这样就能获取到每次的i值。
for (var i = 0; i < 5; i++) {
(function (i) {
setTimeout(function () {
console.log(i) // 0 1 2 3 4
}, 300)
})(i)
}
var 可重复定义
这个很好理解,var是允许定义两次的,不报错误。
var a = 0;
console.log(a); // 0
var a = 1;
console.log(a); // 1
编辑器会在判断有已经声明的同名变量时,会忽略 var 关键字,然后直接赋值,所以如果重复使用的一个声明有一个初始值,那么它是一个赋值语句。如果重复使用的一个声明没有一个初始值,那么它不会对原来存在的变量有任何的影响。这对于 ES5 之前的 JS 是合法的,但是 ES6 后,认为这种重复定义的做法是不科学的, let 和 const 皆不允许作用域内重复一个定义同名变量。
现在我们来讲讲 let
暂存死区
首先,绝对是不允许在let定义变量前使用这个变量的
console.log(a); // ReferenceError: a is not defined
let a = 0;
console.log(a); // 0
let声明不会被提升到当前执行上下文的顶部,从该块级作用域开始,到初始化位置,称作“暂存死区”,所以在对于a的暂存死区中使用a会报Reference错误。
块级作用域
let声明的变量拥有块级作用域,在块级作用域外是访问不到该变量的,而var不同,在for循环中定义的变量可以在外部访问到,这会导致一些意想不到的bug。注意,大括号 {} 是块级作用域,不是说函数作用域。
禁止重定义
let a = 0;
console.log(a); // 0
let a = 1;
console.log(a); // SyntaxError: Identifier 'a' has already been declared
window 对象
在 HTML 中, 全局作用域是针对 window 对象,var关键字定义的全局作用域变量属于 window 对象,而let定义的不属于。注意这是在浏览器环境下,如果是Node则无window对象。
var a = 0;
console.log(window.a) // 0
let b = 1;
console.log(window.b) // undefined
const
其实const和let非常非常类似,let该有的特性,const都有,不同就是,第一,const不允许“修改”变量,第二const必须初始化,而let不需要
const a = 0;
a = 1; // TypeError: Assignment to constant variable
const b; // SyntaxError: Missing initializer in const declaration
不过const定义的不是真正意义上的常量,如果定义的是一个对象或者数组,其实是可以变化的,只不过不能将不同的数据类型分配给他,一般可以记:const初始化定义后,不可使用 = 赋值。
const a = {}
a.b = 1;
console.log(a) // { b: 1 }
a = 1 // TypeError: Assignment to constant variable
var、let和const的区别详解的更多相关文章
- ES6语法:var、let、const的区别详解
今天来说说es6的语法,最基础的也就是var,let,const 的用法与区别了,我们来看看他们之间的恩怨情仇. 首先来说说var,这个只要是学过js的都知道,它是用来声明一个变量的,但是它在开发中也 ...
- ES6 新增声明变量的 var let const 的区别详解
var 如果使用关键字 var 声明一个变量,那么这个变量就属于当前的函数作用域,如果声明是发生在任何函数外的顶层声明,那么这个变量就属于全局作用域. let 1.let 声明的变量具有块作用域的特征 ...
- 李洪强iOS经典面试题155 - const,static,extern详解(面试必备)
李洪强iOS经典面试题155 - const,static,extern详解(面试必备) 一.const与宏的区别(面试题): const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽 ...
- javascript中=、==、===区别详解
javascript中=.==.===区别详解今天在项目开发过中发现在一个小问题.在判断n==""结果当n=0时 n==""结果也返回了true.虽然是个小问题 ...
- Go学习——new()和 make()的区别详解(转载)
这篇文章主要介绍了Go语言中new()和 make()的区别详解,本文讲解了new 的主要特性.make 的主要特性,并对它们的区别做了总结,需要的朋友可以参考下 概述 Go 语言中的 new 和 m ...
- JQ的offset().top与js的offsetTop区别详解
一.前言 最近在做一个图片懒加载的插件,就纵轴(Y轴)而言,我需要时时获取图片的上偏移量,好判断是否已进入视图区域,而我所理解的是offsetTop应该是跟offset().top一样的,然后陷入了因 ...
- jQuery height()、innerHeight()、outerHeight()函数的区别详解
参考来源:http://www.jb51.net/article/84897.htm 代码示例(可复制到编辑器直接打开): <!DOCTYPE html> <html lang=&q ...
- JQ的offset().top与JS的getBoundingClientRect区别详解,JS获取元素距离视窗顶部可变距离
壹 ❀ 引 我在 JQ的offset().top与js的offsetTop区别详解 这篇博客中详细分析了JQ方法offset().top与JS属性offsetTop的区别,并得出了一条offset( ...
- 基于Java的打包jar、war、ear包的作用与区别详解
本篇文章,小编为大家介绍,基于Java的打包jar.war.ear包的作用与区别详解.需要的朋友参考下 以最终客户的角度来看,JAR文件就是一种封装,他们不需要知道jar文件中有多少个.cla ...
随机推荐
- SpringBoot内置的各种Starter是怎样构建的?--SpringBoot源码(六)
注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 温故而知新 本篇接 外部配置属性值是如何被绑定到XxxProperties类属性上的?--SpringBoot源码(五) 温 ...
- 【原创】(求锤得锤的故事)Redis锁从面试连环炮聊到神仙打架。
这是why技术的第38篇原创文章 又到了一周一次的分享时间啦,老规矩,还是先荒腔走板的聊聊生活. 有上面的图是读大学的时候,一次自行车骑行途中队友抓拍的我的照片.拍照的地方,名字叫做牛背山,一个名字很 ...
- Maven pom.xml 添加本地jar包依赖以及打包方法
Maven项目打包时,如果遇到需要添加本地jar包依赖的时候,可以选择两种方法: 1. 安装到本地仓库 第一种方法比较常规,适用于需要添加的jar包也是由maven项目导出,含有pom文件的时候.只需 ...
- npm 安装 electron 出现的奇葩错误
起因 使用yarn安装electron有时稳定,在搭配别的框架时有时又出现无解的错误了,于是打开electron官网,发现: emm,似乎官方对npm情有独钟.于是我遵从官方旨意使用npm安装elec ...
- JavaScript 基础知识汇总目录
一.标签.代码结构.现代模式.变量.数据类型.类型转换 GO 二.运算符.值的比较.交互.条件运算符.逻辑运算符 GO 三.循环 while 和 for .switch语句.函数.函数表达式和箭头函数 ...
- 详解如何实现斗鱼、B站等全局悬浮窗直播小窗口
最近业务需求需要我们直播返回或者退出直播间时,开一个小窗口在全局继续直播视频,先看效果图. 调研了一下当下主流直播平台,斗鱼.BiliBili等app,都是用WindowManger做的(这个你可以在 ...
- Centos7安装Elasticsearch和Kibana
这里使用的6.6.0版本,ES需要JDK环境,对应1.8 Elasticsearch安装: 1.下载:https://elasticsearch.cn/download/ 2.解压: 3.修改配置:j ...
- MyBatis框架——单表查询
Mybatis单表查询,示例 1.创建数据库 /* Navicat MySQL Data Transfer Source Server : localhost Source Server Versio ...
- AspNetCore3.1_Secutiry源码解析_5_Authentication_OAuth
title: "AspNetCore3.1_Secutiry源码解析_5_Authentication_OAuth" date: 2020-03-24T23:27:45+08:00 ...
- 深入Redis客户端(redis客户端属性、redis缓冲区、关闭redis客户端)
深入Redis客户端(redis客户端属性.redis缓冲区.关闭redis客户端) Redis 数据库采用 I/O 多路复用技术实现文件事件处理器,服务器采用单线程单进程的方式来处理多个客户端发送过 ...