目录
01.let 和 const 都是块级作用域。
02.let 和 const声明不存在变量提升,只能先声明再使用,否则会报错。
03.ES6中不允许重复声明,ES5允许
04.const 声明的是一个只读常量,再声明时就需要赋值。
05.let 与const 声明赋值问题
06. const有关知识
07.注意点:
08.案例
在 ES6 中通常用let 和 const 来声明,let 表示变量、const 表示常量,ES5用var声明
特点:
以{ }代码块作为作用域范围 ,只能在代码块里面使用,而var声明的变量全局有效/局部(函数)内部有效.
在代码块内,在声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”
(注意点:如果 const 声明的是一个对象,对象所包含的成员值是可以被修改的。抽象一点儿说,就是对象所指向的地址不能改变,而变量成员 是可以修改的。)
const obj = {}; //对象是一块存储空间,
obj.age = 20; //存储空间没变,修改其成员,并不改变存储空间的地址
console.log(obj);
预解析时:ES6中,let,const在预解析时会在所在代码块中{ }形成一个作用域(暂时性死区) ,但是其定义的变量不会提升
1.const声明的常量在声明时就必须要赋值,不能只声明不赋值
2.const声明的常量不能被修改,且只能初始化赋值一次。
3.当使用常量 const 声明时,请使用大写变量,如:CAPITAL_CASING
4.常在项目中用于一些不变的量:比如说网址。。。。
let 和const 关键词声明的变量不具备变量提升(hoisting)特性
let 和 const 声明只在最靠近的一个代码块中(花括号内)有效
const 在声明时必须被赋值
const 如何做到变量在声明初始化之后不允许改变的?使用 const 声明复杂类型对象时要慎重。
eg1:易错:要知道脚本运行初,在全局作用域先扫描关键字 var a;
分析:if(false)不管if括号里面是false或者true,代码运行初,就会扫描到关键字 var a;进行提升,然后console.log(a);这里就会运行出undefined,不是报错哦。
eg2:分析下面代码
分析:进入if里面,因为里面有let,会把if(){代码块}形成一个作用域(相当于一个密闭空间"暂时性死区",运行期间,把let所在代码块封死),但是let声明的变量不会有提升效果,所以if里面的 console.log(a);就会报错,导致程序停止执行
分析: 因为false判定为假,所以程序不执行if语句,就相当于 let a = 90; console.log(a); 所以结果为90
//这是一段错误代码,分析为什么是错误的代码
分析: 程序在预解析时,扫描到if语句里面的var a = 20; var声明的变量不会产生作用域,所以var a 属于全局变量并且要提升,相当于下面这种
也就形成了用var 和 let 分别声明同一作用域的同一变量 会报错。
但如果是在不同作用域声明同一变量就不会报错:
eg3: 一道经典面试题:
注解: setTimeout函数
setTimeout() 是属于 window 的方法,该方法用于在指定的毫秒数后调用函数或计算表达式。语法格式可以是以下两种
语法:
setTimeout(要执行的代码, 等待的毫秒数) setTimeout(JavaScript 函数, 等待的毫秒数)
分析:一看到程序,不就一个简单的for循环嘛,结果不就为:0,1,2,3,4,5,6,7,8,9
嘛,但真实结果为:10、10、10、10、10、10、10、10、10、10 ,为什么呢?
深入分析这题:
结果为10个10的原因是for循环中使用setTimeout涉及到了异步机制。说到异步机制那就要说一下
JS的运行机制:
JS是单线程环境,也就是说代码的执行是从上到下,依次执行。也就是同一个时间只能做一件事。单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。JavaScript将所有任务分成两种,一种是同步任务,另一种是异步任务。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。在所有同步任务执行完之前,任何的异步任务是不会执行的。
异步执行的运行机制如下:
1. 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
2. 主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
3. 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
4. 主线程不断重复上面的第三步。
主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会循环反复。
一般来说:有以下4种会放入异步任务队列:
setTimeout和setlnterval
DOM事件
ES6中的Promise
Ajax异步请求
现在来看这道面试题:
代码中的for循环是个同步任务,setTimeout是个异步任务,所以把for循环执行完毕后(i=10)才会执行异步任务setTimeout()函数,所以导致输出了10个10(间隔输出)的结果。
具体执行步骤如下:
1.for循环为同步任务,先执行产生了十个定时器。
(由于这里的for循环不是独立的代码块,声明的 i 为全局变量,遍历完成相当于全局环境i=10;)这里理解:for循环,循环一次,
2.同步任务for遍历完了再执行异步任务的定时器。
(此时定时器运行环境与for循环同级,即在全局环境i=10下运行,因此输出10个10)
画个草图(帮助理解,我感觉是这样),草图,草图,草图!!!
那么怎么才能输出正确答案0、1、2、3、4、5、6、7、8、9而不是连续的10个10呢?
分析:利用let声明的变量会使得所在代码块形成作用域 "暂时性死区"来做
草图大概就是
这里输出 答案0、1、2、3、4、5、6、7、8、9还有其它方法,这里因为是主要讲let,所以只讲了一种。更多来自:
http://t.csdn.cn/PXMMS
本文很多内容也是借鉴该博主。
1.共同点:都是可以声明变量的。
2.区别:
01.var 具有变量提升的机制,let和const没有变量提升的机制
02.var 可以多次声明同一个变量,let和const不可以多次声明同一个变量(只能修饰一次)
03.var , let 声明变量,const声明常量,var和let声明的的变量可以再次赋值,但是const不可以再次赋值了。
注意点:如果const的是一个引用数据,里面的数据改了,但是引用地址没改,也不会报错
04. var 声明的变量没有自身作用域,let 和const声明的变量有自身的作用域("暂时性死区"),在该区域外面,访问不到该区域里面的数据。