ES5-ES6-ES7_let关键字声明变量
let命令的介绍
let是ECMAScript6中新增的关键字,用于声明变量。它的用法类似于var
var a = 3 let b = 4
let变量的声明
let 命令的特点不允许在同一作用域下声明已经存在的变量,也就是不能重复声明(不允许多个变量的变量名相同)
// var a = 1; // var a = 3;//重复声明变量不会报错,a变成了3 // let b = 4; // let b = 6;//会报错:Identifier 'b' has already been declared (变量名已经存在) var a = 2; let a = 3; //这样也会报错:SyntaxError: Identifier 'a' has already been declared
let 命令的特点—没有预解析
var
命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined
。这种现象多多少少是有些奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用。
为了纠正这种现象,let
命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。
console.log(a)//不会报错,会显示a这个变量的值为undefined var a = 1; console.log(b)//会报错:b is not defined(…),该变量未定义 let b = 4;
变量a
用var
命令声明,会发生变量提升,即脚本开始运行时,变量a
已经存在了,但是没有值,所以会输出undefined
。
变量b
用let
命令声明,不会发生变量提升。这表示在声明它之前,变量b
是不存在的,这时如果用到它,就会抛出一个错误。
let 命令的特点—块级作用域
一对{}包括的区域成为代码块,块级作用域指一个变量或者函数只有在该区域才起作用
{ let a = 10; var b = 1; } console.log(a) // ReferenceError: a is not defined. console.log(b) // 1
let命令的特点—暂时性死区
let f = 10; function fn() { f = 7; //暂时性死区 let f = 2; } fn(); //执行结果依然报错,原因是在fn函数内又声明了一遍变量f
let f = 10; function fn() { f = 7; //暂时性死区 // let f = 2; // 这里重复声明f变量会报错 console.log(f) // 打印结果是7 } console.log(f) // 打印结果是10 fn();
let在for循环中的应用
在实验之前先来看一下var在for循环中的应用中会产生什么样的问题和解决问题的方法以及案例
for(var i = 0;i<10;i++){ setTimeout(function(){ console.log(i)//打印结果是10个10,因为for执行了10次 ,i的值已经到了10,setTimeout才开始第一次执行 }) } for(var i = 0;i<10;i++){ (function(i){ //这里使用闭包的方式 setTimeout(function(){ console.log(i); //打印结果依次是:1,2,3,4,5,6,7,8,9,10 }) })(i) }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button>1</button> <button>2</button> <button>3</button> <button>4</button> <button>5</button> </body> </html> <script> var btns = document.querySelectorAll('button'); // for(var i = 0;i<btns.length;i++){ // btns[i].onclick = function () { // console.log(i) // } // } // for(var i = 0;i<btns.length;i++){ // btns[i].index = i; //自定义属性 // btns[i].onclick = function () { // console.log(this.index) // } // } for (var i = 0;i<btns.length;i++){ (function (i) { btns[i].onclick = function () { console.log(i) } })(i) } </script>
上面代码中我们可以使用使用自定义属性的方式解决这个问题也可以使用闭包的方式解决这个问题
再来看一下使用let在for循环中的应用会不会出现上述的问题,在循环语句之内是一个父作用域,在循环体之中是一个子作用域
for(let i = 0;i<10;i++){ setTimeout(function(){ console.log(i); //打印结果依次是:1,2,3,4,5,6,7,8,9,10 }) }
for(let i = 0;i<10;i++){ let i = 10; console.log("for:"+i); //结果都是10 } console.log(i); //报错:ReferenceError: i is not defined
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button>1</button> <button>2</button> <button>3</button> <button>4</button> <button>5</button> </body> </html> <script> var btns = document.querySelectorAll('button'); for(let i = 0;i<btns.length;i++){ btns[i].onclick = function () { console.log(i) } } </script>
下面来一个日常工作中非常常见的需求——就是选项卡功能
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> div{ display: none; } .show{ display: block; } .active{ background-color: yellow; } </style> <script type="text/javascript"> "use strict" window.onload = function(){ var tabs = document.getElementsByTagName('input'); var divs = document.getElementsByTagName('div'); for(var i=0;i<tabs.length;i++){ tabs[i].index = i; tabs[i].onclick = function(){ for(var j=0;j<tabs.length;j++){ divs[j].className = ''; tabs[j].className = ''; } this.className = 'active'; divs[this.index].className = 'show'; } } // var tabs = document.getElementsByTagName('input'); // var divs = document.getElementsByTagName('div'); // // for(let i=0;i<tabs.length;i++){ // // tabs[i].onclick = function(){ // for(let j=0;j<tabs.length;j++){ // divs[j].className = ''; // tabs[j].className = ''; // } // this.className = 'active'; // divs[i].className = 'show'; // } // } } </script> </head> <body> <input type="button" value="tab1" class="active"> <input type="button" value="tab2"> <input type="button" value="tab3"> <div class="show">div1</div> <div>div2</div> <div>div3</div> </body> </html>