深入理解var,let,const的区别

来源:网络 文章列表 2019-08-10 8
学习JavaScript大家最先接触的就是var,let2个关键词吧!var,let都是用来声明变量的,但是你真的理解这二者之间的区别吗?let/const是使用区块作用域;var是使用函数作用域。在let/const声明之前就访问对应的变量与常量,会抛出ReferenceError错误;但在var声明之前就访问对应的变量,则会得到undefined。

学习JavaScript大家最先接触的就是var,let2个关键词吧!var,let都是用来声明变量的,但是你真的理解这二者之间的区别吗?

我想大家脑子里第一个想到的就是 for 循环的那个例子

let:

for (let i = 0; i < 10; i++) {
  // ...
}
console.log(i); 
// ReferenceError: i is not defined

上面代码中,计数器i只在for循环体内有效,在循环体外引用就会报错。

var:

for (var i = 0; i < 10; i++) {
  // ...
}
console.log(i)

i 等于 10

上面代码中,变量ivar命令声明的,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会+1,发生改变,最终console.log(i)输出10

但是如果你仅仅理解到这一步是不够的,为啥呢?

请看这段代码:

a = 'javascript';
var a;
console.log(a);

b = 'js'
let b;
console.log(b)

请问,2者输出啥,这2者可都是在全局下的呢?

如果要深入理解var ,let/const之间的区别,我们需要用到作用域、和词法分析的知识。

我们先来了解下js引擎在读取js代码时的2个步骤吧!

  • 第一个步骤是解释
  • 第二个步骤是执行

所谓解释就是会先通篇扫描所有的Js代码,然后把所有变量声明,函数声明提升到顶端,第二步是执行赋值啊,运算啊等一系列操作。

回答我们上面的那段代码,我们看下结果

a = 'javascript';
var a;
console.log(a); // javascript

b = 'js'
let b;
console.log(b) // b is not defined

下面我们分析下出现这2个结果的深层次原因

 

变量声明和初始化

a = 'javascript';
var a;
console.log(a);

请思考a输出什么?

console.log(b);
var b = 'javascript'

请思考b又输出什么?

 

 

答案是 a 输出 javascript  b输出 undefined

js引擎遇到 script 标签的话 js 就进行预解析,将变量 var 和 function 声明提升,但不会执行 function,然后就进入上下文执行,上下文执行还是执行预解析同样操作,直到没有 var 和 function,就开始执行上下文。

举例:

a=5;
show();
var a;
function show(){};

预解析:

function show(){};
var a;
a=5;
show();

需要注意的是函数声明提升直接把整个函数提到执行环境的最顶端

let/const声明的变量,也是有提升(hoist)的作用。这个是很容易被误解的地方,实际上以let/const声明的变量也是会有提升(hoist)的作用。提升是JS语言中对于变量声明的基本特性,只是因为let/const暂时性死区的作用并不会像使用var来声明变量,只是会得到undefined而已,现在则是会直接抛出ReferenceError错误,而且很明显的这是一个在运行期间才会出现的错误。

比如:

console.log(a) // ReferenceError: a is not defined.
console.log(b) // 1
let a = 10;
var b = 1;

那么我们现在来总结下var let/const的区别?

  • let/const是使用区块作用域;var是使用函数作用域。
  • 在let/const声明之前就访问对应的变量与常量,会抛出ReferenceError错误;但在var声明之前就访问对应的变量,则会得到undefined。

那么let为什么会抛出 ReferenceError 错误呢?

let/const拥有“暂时性死区(TDZ)”。

什么是暂时性死区?

当程序的控制流程在新的作用域(module, function或block作用域)进行实例化时,在此作用域中的用let/const声明的变量会先在作用域中被创建出来,但因此时还未进行词法绑定,也就是对声明语句进行求值运算,所以是不能被访问的,访问就会抛出错误。所以在这运行流程一进入作用域创建变量,到变量开始可被访问之间的一段时间,就称之为TDZ(暂时死区)。

S6 规定暂时性死区和let、const语句不出现变量提升,主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。这样的错误在 ES5 是很常见的,现在有了这种规定,避免此类错误就很容易啦~

腾讯云限量秒杀

1核2G 5M 50元/年 2核4G 8M 74元/年 4核8G 5M 818元/年 CDN流量包 100GB 9元

版权声明

本站部分原创文章,部分文章整理自网络。如有转载的文章侵犯了您的版权,请联系站长删除处理。如果您有优质文章,欢迎发稿给我们!联系站长:
愿本站的内容能为您的学习、工作带来绵薄之力。

评论

  • 随机获取
点击刷新
精彩评论

友情链接