JavaScript中ES6语法Let,Const变量定义解析
一、变量提升(变量预解析)
这是我们首先要了解的,也是必须要清楚的一个概念,那到底什么是变量提升呢?
JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。JavaScript 解析器在运行 JavaScript 代码的 时候分为两步:预解析和代码执行。
l 预解析:在当前作用域下, JS 代码执行之前,浏览器会默认把带有 var 和 function 声明的变量在内存中 进行提前声明或者定义。
l 代码执行: 从上到下执行JS语句。
JS代码运行的时候确实是一行一行执行的,但是在实行前会有一个预解析的过程,相当于把所有的代码先全部扫描一遍,把带有 var 和 function 声明的变量先存在内存中,也可以说提到整体的代码前面去。
学习预解析能够让我们知道为什么在变量声明之前 访问变量的值是 undefined,为什么在函数声明之前就可以调用函数。
我们来看一段简单的代码
console.log(num); // 结果是多少? var num = 10; // ?
答案很简单是undefined
为什么?
1变量提升
变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升。
所以我们来看一下这段代码的解析过程
其实相当于 Var num; Log(num); num = 10;
2函数提升
函数的声明会被提升到当前作用域的最上面,但是不会调用函数。
fn(); function fn() { console.log('123'); }
答案:123
3相关例题
接着我们看几个相关案例题
案例一
结果是几?
var num = 10; function fn(){ console.log(num); var num = 20; console.log(num); } fn();
undefined
20
案例二
结果是几?
var a = 18; f1(); function f1() { var b = 9; console.log(a); console.log(b); var a = '123'; }
undefined
9
案例三
结果是几?
f1(); console.log(c); console.log(b); console.log(a); function f1() { var a = b = c = 9; console.log(a); console.log(b); console.log(c); }
9 9 9 9 9 报错
这里提一下:var a = b = c = 9; 这句话的本质上是这样的 Var a=9,b=9,c=9 注意 只有a是用了var的 ,所以a是局部变量,b c是全局变量
如果要集体申明应该是var a=9,b=9,c=9。但是其实现在实际开发中var用的很少。
二、Let
ES6中新增的用于声明变量的关键字。
特点:
A、不会进行预解析,结果会报错
B、与forEach()中的变量类似,每次执行都会定义一个互相之间不影响的新变量
C、不能重复定义变量名称,一个变量名称只能定义一次
D、定义的变量如果在中,则只能在中被执行调用,其他位置都不可以。所以在不同中,定义的变量名称是可以重复之用的
E、在循环中最好只用let定义
- let声明的变量只在所处于的块级有效
注意:使用let关键字声明的变量才具有块级作用域,使用var声明的变量不具备块级作用域特性。
if (true) { let a = 10; } console.log(a) // a is not defined
- 不存在变量提升
console.log(a); // a is not defined 注意这个地方是会报错的,而不是undefined let a = 20;
- 暂时性死区
Let会使当前的作用域形成块级作用域,也就是说当if里面使用了let后, 括号里面的tmp和外面申明的tmp完全没有关系了,这也叫暂时性死区
var tmp = 123; if (true) { tmp = 'abc'; // tmp is not defined let tmp; }
let经典面试题
var arr = []; for (var i = 0; i < 2; i++) { arr[i] = function () { console.log(i); } } arr[0](); arr[1]();
答案:2 2
此题的关键点在于变量i是全局的,函数执行时输出的都是全局作用域下的i值。 打印i是会向上查找i的申明,但是只查到了循环体中的全局申明,所以i是全局变量 当下面数组调用函数时,for循环早就遍历完了,此时的i已经是2了
let经典面试题
let arr = []; for (let i = 0; i < 2; i++) { arr[i] = function () { console.log(i); } } arr[0](); arr[1]();
此题的关键点在于每次循环都会产生一个块级作用域,每个块级作用域中的变量都是不同的, 函数执行时输出的是自己上一级(循环产生的块级作用域)作用域下的i值
每个块级作用域都是相互独立的,不受相互影响的
三、Const
作用:声明常量,常量就是值(内存地址)不能变化的量。
特点:
A、在js中,const定义的变量成为常量,不能被重复赋值,数据已经定义,不能修改
B、const也是定义在中,不能在外调用
C、const定义的是对象、数组、函数、引用数据类型。其中只要引用数据类型的地址没变化,就可以改变引用数据类型中的单元存储的数据
D、const不会进行预解析,结果会报错
- 具有块级作用域
if (true) { const a = 10; } console.log(a) // a is not defined
- 声明常量时必须赋值
const PI; // Missing initializer in const declaration
- 常量赋值后,值不能修改。
声明了一个常量,代表这个识别名称的参照(reference)是唯读的(read-only),并不代表这个参照赋到的值是不可改变的(immutable),"const"只是针对存取层级的限制(access limitations),并不是不可改变性(immutability)。
上面这段在讲什么呢?实际上就是简单数据类型例如字符、数值常量赋值后不能更改,但是复杂数据类型,例如数组、对象,情况有所出入。
当对整个数组或者对象进行重新赋值时,是不被允许的,而修改里面的属性时是可以的,例如案例代码所示。
本质原理就是常量值对应的内存地址并不能变化,重新赋值等于修改内存地址,而修改属性则没有关系。
const PI = 3.14; PI = 100; // Assignment to constant variable. const ary = [100, 200]; ary[0] = 'a'; ary[1] = 'b'; console.log(ary); // ['a', 'b']; ary = ['a', 'b']; // Assignment to constant variable.
额外
1声明常量时建议使用const还是let
这个问题网上的争议很多,有人说使用const有人说使用let,我仅我个人的理解来说我一下我的认识。
我喜欢还是用const (这是一个非常个人化主观化的观点,你说你喜欢用let当然可以)
const可以用在对象、数组与函数上,常量一声明时就要赋值,犯错的机会会减少很多。
JS引擎也可以作优化。虽然JS语言上并没有感受差异,但实际上引擎里有区分出常量与变量,而最重要的是因为JS语言是弱(动态)类型的脚本语言,常量一声明就赋值,代表它立即决定好是什么类型与值,自然效能比变量好得多。也可以理解说因为const声明的常量是固定的,内存不需要实时监测值的变化,所以比其他变量的内存占有率更少
2函数方法中的const
我不知道有没有人和我一样,有一段时间一直有个困惑,就是在函数中,或者方法中,用const申明变量,不是说const是不能再被赋值的吗?函数会调用很多次,为什么不报错?
其实后来一想很简单,因为函数每次执行完之后就会销毁了。。。。
- 定义变量var与ES6的let,const区别与应用
- 简说ES6中的变量定义:let、const
- 简说ES6中的变量定义:let、const
- JS变量中有var定义和无var定义的区别以及es6中let命令和const命令
- [Wondgirl]ECMAScript6(ES6)(二)变量let、var和常量const的定义和区别
- ES6语法:var、let、const的区别详解
- ECMAScript(ES6)let 和 const 命令,变量的解构赋值
- ES6中let、const的区别及变量的解构赋值操作方法实例分析
- [ES6常用语法]之let与const
- ES602、es6 的变量 let、const
- 【ES6】let、const变量提升的验证,以及TDZ死区的理解
- ES6语法总汇—— let 和 const
- ES6语法let、const与var的区别-总结
- ES6 ---声明变量 let const 笔记
- js中三种定义变量 const, var, let 的区别
- ES6 语法---变量的赋值与解析
- javascript 三种变量申明方式var、let、const
- es6新语法:let、const
- es6语法之一()let和const作用域
- [ES6语法1]let和const