详解js中let与var声明变量的区别


Posted in Javascript onApril 05, 2020

ES6 新增了let命令,用来声明局部变量,所声明的变量,只在let命令所在的代码块内有效,而且有暂时性死区的约束。

1.ES6可以用let定义块级作用域变量

代码如下:

function f1(){
  {
   var a = 10;
   let b = 20;
  }
  console.log(a); // 10
  console.log(b); // Uncaught ReferenceError: b is not defined
 }
 f1();

说明:在ES6之前只有全局作用域和函数作用域,在ES6中新增了块级作用域,用{}花括号表示。var 声明的变量a在花括号外面仍然是会起作用的,但是let声明的变量b只有在花括号里面才会起作用的,在块级作用域内。

2.let配合for循环的独特应用

代码如下:

function f2(){
  var i = 5;
  for(var i=0;i<=10;i++){

  }
  console.log(i); // 11

  var j = 5;
  for(let j=0;j<=10;j++){

  }
  console.log(j); // 5

 }
 f2();

说明:let非常适合用于for循环内部的块级作用域,在for循环当中,每一次的执行都是一个全新的独立的块级作用域。使用let声明的变量在for循环当中不会受到循环体外面的影响,不会受到变量污染,不会发生改变。对于var声明的变量i会受到for循环的影响,受到变量污染,而let声明的变量j不会受到for循环的影响。

3.let没有变量提升与暂时性死区

代码如下:

function f3(){

  // 变量提升
  function f31(){
   console.log(a); // undefined
   var a = 10;

   console.log(b); // Uncaught ReferenceError: b is not defined
   let b = 10;
  }
  f31();

说明:在ES6中,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。暂时性死区(TDZ):在代码块内,使用let命令声明变量之前,该变量都是不可用的。在f31函数中,用var声明的变量a发生了变量提升,打印出的值为undefined 未定义,而用let声明的变量b报错Uncaught ReferenceError,不会发生变量提升。在f32函数中,用使用let命令声明的变量a之前,都属于变量a的暂时性死区,形成封闭作用域,该变量都是不可用的,会报错,Uncaught ReferenceError: a is not defined。在let声明变量后,它是一个未定义的变量。当再给变量a进行赋值操作以后,它的值可以正常打印出来。

4.let变量不能重复声明

代码如下:

function f4(){
  let a = 10;
  let a = 20;
  console.log(a); // Uncaught SyntaxError: Identifier 'a' has already been declared

  let b = 10;
  var b = 20;
  console.log(b); // Uncaught SyntaxError: Identifier 'b' has already been declared

 }
 f4();

说明:let不允许在相同作用域内,重复声明同一个变量,否则报错。在函数f4中,无论是用两个let声明同一个变量a,还是一个let声明变量b和一个var声明变量b,都是会报错的,Uncaught SyntaxError: Identifier ‘a' has already been declared 和 Uncaught SyntaxError: Identifier ‘b' has already been declared , 所以不能够重复声明同一个变量。

JS中的let和var的区别补充

最近很多前端的朋友去面试被问到let和var的区别,其实阮一峰老师的ES6中已经很详细介绍了let的用法和var的区别。我简单总结一下,以便各位以后面试中使用。

ES6 新增了let命令,用来声明局部变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效,而且有暂时性死区的约束。

先看个var的常见变量提升的面试题目:

//题目1:
var a = 99;      // 全局变量a
f();          // f是函数,虽然定义在调用的后面,但是函数声明会提升到作用域的顶部。 
console.log(a);    // a=>99, 此时是全局变量的a
function f() {
 console.log(a);   // 当前的a变量是下面变量a声明提升后,默认值undefined
 var a = 10;
 console.log(a);   // a => 10
}

// 输出结果:
undefined
10
99

如果以上题目有理解困难的童鞋,请系统的看一下老马的免费JS高级视频教程。

ES6可以用let定义块级作用域变量

在ES6之前,我们都是用var来声明变量,而且JS只有函数作用域和全局作用域,没有块级作用域,所以{}限定不了var声明变量的访问范围。

例如:

{ 
 var i = 9;
} 
console.log(i); // 9

ES6新增的let,可以声明块级作用域的变量。

{ 
 let i = 9;   // i变量只在 花括号内有效!!!
} 
console.log(i); // Uncaught ReferenceError: i is not defined

let 配合for循环的独特应用

let非常适合用于 for循环内部的块级作用域。JS中的for循环体比较特殊,每次执行都是一个全新的独立的块作用域,用let声明的变量传入到 for循环体的作用域后,不会发生改变,不受外界的影响。看一个常见的面试题目:

for (var i = 0; i <10; i++) { 
 setTimeout(function() { // 同步注册回调函数到 异步的 宏任务队列。
  console.log(i);    // 执行此代码时,同步代码for循环已经执行完成
 }, 0);
}
// 输出结果
10  共10个
// 这里面的知识点: JS的事件循环机制,setTimeout的机制等

如果把 var改成 let声明:

// i虽然在全局作用域声明,但是在for循环体局部作用域中使用的时候,变量会被固定,不受外界干扰。
for (let i = 0; i < 10; i++) { 
 setTimeout(function() {
  console.log(i);  // i 是循环体内局部作用域,不受外界影响。
 }, 0);
}
// 输出结果:
0 1 2 3 4 5 6 7 8 9

let没有变量提升与暂时性死区

用let声明的变量,不存在变量提升。而且要求必须 等let声明语句执行完之后,变量才能使用,不然会报Uncaught ReferenceError错误。
例如:

console.log(aicoder);  // 错误:Uncaught ReferenceError ...
let aicoder = 'aicoder.com';
// 这里就可以安全使用aicoder

ES6 明确规定,如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

let变量不能重复声明

let不允许在相同作用域内,重复声明同一个变量。否则报错:Uncaught SyntaxError: Identifier 'XXX' has already been declared

例如:

let a = 0;
let a = 'sss';
// Uncaught SyntaxError: Identifier 'a' has already been declared

总结

ES6的let让js真正拥有了块级作用域,也是向这更安全更规范的路走,虽然加了很多约束,但是都是为了让我们更安全的使用和写代码。

以上所述是小编给大家介绍的let与var声明变量区别详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
jquery $.ajax各个事件执行顺序
Oct 15 Javascript
推荐30个新鲜出炉的精美 jQuery 效果
Mar 26 Javascript
js字符串转换成数字与数字转换成字符串的实现方法
Jan 08 Javascript
input标签内容改变的触发事件介绍
Jun 18 Javascript
javascript实现3D变换的立体圆圈实例
Aug 06 Javascript
js实现文字滚动效果
Mar 03 Javascript
jQuery使用getJSON方法获取json数据完整示例
Sep 13 Javascript
Javascript 创建类并动态添加属性及方法的简单实现
Oct 20 Javascript
AngularJS使用拦截器实现的loading功能完整实例
May 17 Javascript
解决bootstrap中使用modal加载kindeditor时弹出层文本框不能输入的问题
Jun 05 Javascript
Egg.js 中 AJax 上传文件获取参数的方法
Oct 10 Javascript
原生JS实现音乐播放器
Jan 26 Javascript
webpack中如何加载静态文件的方法步骤
May 18 #Javascript
微信小程序实现录音时的麦克风动画效果实例
May 18 #Javascript
vue+egg+jwt实现登录验证的示例代码
May 18 #Javascript
egg.js的基本使用和调用数据库的方法示例
May 18 #Javascript
inquirer.js一个用户与命令行交互的工具详解
May 18 #Javascript
webpack 代码分离优化快速指北
May 18 #Javascript
如何实现小程序tab栏下划线动画效果
May 18 #Javascript
You might like
在PHP里得到前天和昨天的日期的代码
2007/08/16 PHP
Laravel框架模板继承操作示例
2018/06/11 PHP
PHP attributes()函数讲解
2019/02/03 PHP
JS限制Textarea文本域字符个数的具体实现
2013/08/02 Javascript
JQuery实现鼠标滑过显示导航下拉列表
2013/09/12 Javascript
js、jquery图片动画、动态切换示例代码
2014/06/03 Javascript
鼠标移到图片上变大显示而不是放大镜效果
2014/06/15 Javascript
jQuery打印图片pdf、txt示例代码
2014/07/22 Javascript
jQuery实现html表格动态添加新行的方法
2015/05/28 Javascript
Bootstrap3制作自己的导航栏
2016/05/12 Javascript
浅谈js控制li标签排序问题 js调用php函数的方法
2016/10/16 Javascript
Angular的$http的ajax的请求操作(推荐)
2017/01/10 Javascript
canvas实现图像截取功能
2017/02/06 Javascript
VueJS组件之间通过props交互及验证的方式
2017/09/04 Javascript
Vue2.5通过json文件读取数据的方法
2018/02/27 Javascript
详解element-ui中form验证杂记
2019/03/04 Javascript
vue中使用v-model完成组件间的通信
2019/08/22 Javascript
js单线程的本质 Event Loop解析
2019/10/29 Javascript
基于Vue中使用节流Lodash throttle详解
2019/10/30 Javascript
js实现从右往左匀速显示图片(无缝轮播)
2020/06/29 Javascript
JavaScript 常见的继承方式汇总
2020/09/17 Javascript
Python修改Excel数据的实例代码
2013/11/01 Python
详解Python中time()方法的使用的教程
2015/05/22 Python
在Django框架中设置语言偏好的教程
2015/07/27 Python
基于numpy.random.randn()与rand()的区别详解
2018/04/17 Python
python实现验证码识别功能
2018/06/07 Python
Python -m参数原理及使用方法解析
2020/08/21 Python
python 发送get请求接口详解
2020/11/17 Python
亚洲最大的运动鞋寄售店:KicksCrew
2020/11/26 全球购物
办公自动化毕业生求职信
2014/03/09 职场文书
禁毒宣传标语
2014/06/19 职场文书
学校领导班子成员查摆问题及整改措施
2014/10/28 职场文书
2014年文明创建工作总结
2014/11/25 职场文书
2014年英语教研组工作总结
2014/12/06 职场文书
软件项目经理岗位职责
2015/04/01 职场文书
新郎结婚感言
2015/07/31 职场文书