对于写js的人来讲,这三个关键字再熟悉不过了吧。ES6以前,只要是定义变量,哪儿都丢一个var过去,都不须要多想的。到了ES6标准,忽然新增了两个新玩意儿"const"和"let"。之前是没得选,如今在定义变量的时候老是得想一下应该用哪个了。那么既然已经有了var能够定义变量了,为何还须要提供新的东西来提升使用复杂度呢?咱们必须相信,一个新事物可以流行或替代旧的事物,一定是之前的东西存在缺点和不足,新东西可以解决这些问题。那么接下来咱们就来聊一聊这几个关键字之间的关系。html
按照惯例,咱们先罗列几个常识:数组
问:var到底有什么问题,以致于ES6中须要提供const和let来定义变量?bash
1.解决ES5使用var初始化变量时会出现的变量提高问题函数
案例1:变量定义前置ui
console.log('var: ',a1); // undefined
console.log('let: ',a2); // 报错
var a1 = '这是var变量';
let a2 = '这是let变量';复制代码
打印结果:lua
缘由:程序在检查完语法问题以后,会进行预编译,预编译就是在执行代码会把全部的变量声明和函数声明预先处理,换句话说就是将函数以及变量先提出来,var定义的变量会提出来,并赋值undefined,函数会提出但不传值,不执行。可是let定义的变量不动。因此上面的代码在预编译的时候就等价于:spa
var a1;
console.log(a1); // undefined
console.log(a2); // 报错
a1 = '这是var变量';
let a2 = '这是let变量';复制代码
案例2:内层变量覆盖外层变量.net
var a = 'outerA';
function fn(){
console.log(a); // undefined;
var a = 'innerA';
console.log(a);
}复制代码
我记得对于外面定义的变量,函数内部是能够访问的,为何到了上面的例子,第一个打印的a确实undefined呢?3d
缘由是由于在函数内部又定义了一个a变量,内层变量在预编译的时候,提高到了函数顶部,至关于:code
var a = 'outerA';
function fn(){
var a ;
console.log(a); // undefined;
console.log(window.a); // outerA
a = 'innerA'; // 单纯的赋值
console.log(a);
}复制代码
案例3:函数提高优先于变量提高
fn1();
function fn1(){
console.log(a);
}
var a = 'outerA';复制代码
函数执行了,可是获取到的a是undefined,上面代码就至关于:
function fn1(){
console.log(a);
}
var a;
fn1();
a = 'outerA';复制代码
那么怎么才能获取到a呢?很简单,函数在变量赋值以后调用就好了呀~
2. var在for和if这种块级做用域中,变量会泄露
咱们来看一个很是经典的循环例子:
经过循环,将计算a数组中每一个数字平方的函数一一对应存储在aFn这个数组中,记住,存的是函数,不是结果值。
var a = [0,1,2,3,4,5,6,7,8,9,10]
var aFn = [];
for (var i = 0; i < 10; i++) {
aFn[i] = function() {
return a[i]**2;
}
}
//执行aFn中函数
for (var j = 0; j < 10; j++) {
console.log(aFn[j]());
}复制代码
结果:
缘由:上面案例1咱们已经提到过,程序在执行以前会进行预编译,函数声明提出来,不传值不执行,函数自身的做用域在这一个阶段已经产生了。因为var定义的变量,没有块做用域的概念,因此循环中的i处于全局做用域。当咱们调用aFn[j](),正式执行函数的时候,其实i的值都是10,以致于结果都是aFn数组中的每个函数执行的结果都是100。那咱们来看看let定义的结果:
var a = [0,1,2,3,4,5,6,7,8,9,10]
var aFn = [];
for (let i = 0; i < 10; i++) {
aFn[i] = function() {
return a[i]**2;
}
}
//执行aFn中函数
for (var j = 0; j < 10; j++) {
console.log(aFn[j]());
}复制代码
结果:
缘由:函数在预编译的时候已经肯定本身的做用域了,由于let是块级做用域,每一个循环至关于定义了属于本身的块级做用域,无论何时执行,函数取得的i都是各自块内部的值。
上面的示例只是为了讲解var存在的问题,以及let和块级做用域在程序中解决了一个什么样的问题(变量泄露),固然若是单从结果而言,打出aFn这样一个结果列表,彻底不必将很差控制的函数做为数组项存储,当即执行函数存结果,遍历结果就好了,这里切不要纠结这种问题。
var a = [0,1,2,3,4,5,6,7,8,9,10]
var aFn = [];
for (var i = 0; i < 10; i++) {
aFn[i] = function() {
return a[i]**2;
}()
}
//执行aFn中函数
for (var j = 0; j < 10; j++) {
console.log(aFn[j]);
}复制代码
接下来简单说一下const这个关键字
const用来定义常量,使用时必须初始化(即必须赋值),只能在块做用域里访问,并且不能修改。const 和 let 的做用域是一致的,不一样的是 const 变量一旦被赋值,就不能再改变了;
这里说的不可变是指数据的内存地址,对于基本数据类型的数据来讲,数据自己是存在栈内存的,因此const定义的变量就至关于一个常量,不可修改。可是对于引用数据类型(函数、数组、对象)来讲,只要是自己内存地址不变,里面数据的修改是能够的。
常量:
const name = 'moose';
name = 'Lavar';复制代码
结果:
引用数据类型:
const moose = {
id: '0001',
age: '18'
}
moose.id ='0002';
console.log(moose.id);复制代码
结果:
到此为止,咱们大致的梳理了var、let以及const三个变量定义关键字相关的内容
特别感谢提供相关内容参考:
附:感谢您的阅读,但愿对您有所帮助。若是以上内容中存在疑问和错误,欢迎留言或者私信。