关于ES6的let命令

1、let的基本用法以及let和var的区别

(1) let与var一样是用来声明变量的,与var的区别是let所声明的变量,只在let所在的代码块内有效

eg1:
{
  let a = 10;
  var b = 1;
}
eg2:
for(let i=0;i<5;i++){
console.log(i);//输出1,2,3,4
}
console.log(i);//i is not defined

可以看上面这段代码,也就是说let声明的变量只能在{ }里面获取,在{}外面是获取不到,但是var声明的变量在{}内外都能获取到

(2) let未先声明变量就用变量会编译出错,但是var不会,会输出undefined
另外let不允许在同一作用域下声明已经存在的变量,即在同一作用域下不可以声明两个变量名相同的变量,会直接报错,但是var不会,可见let比var更加规范化

console.log(a);//报错:a is not defined
let a=1;

console.log(a);//undefined
var a=1;
}

(3) let在for循环内作用域问题1

{
for (let i = 0 /* 作用域a */; i < 3; console.log("in for expression", i), i++) {
    let i; //这里没有报错,就意味着这里跟作用域与上面a的作用域不同
    console.log("in for block", i);
}

(4) let在for循环内作用域问题2
1)关于下面eg1这段代码为什么输出结果是10呢?因为for里面的i的作用域是整个外部区域,所以,当调用a6的时候,其实运行的是console.log(i),而此时因为跑完循环,i的值是10,所以输出10

2)关于eg2输出结果是6,因为在ES标准中,有一段是关于CreatePerIterationEnvironment,也就是for语句每次循环所要建立环境的步骤,里面有提及有关词法环境的相关步骤(LexicalEnvironment),这与使用let时会有关。所以,如果你使用了let而不是var,let的变量除了作用域是在for区块中,而且会为每次循环执行建立新的词法环境(LexicalEnvironment),拷贝所有的变量名称与值到下个循环执行。

eg1使用var:
var a = [];
for (var i = 0; i < 10; i++) {
  // 作用域a
  a[i] = function () {
    // 作用域b
    console.log(i);
  };
}
a[6](); // 10


eg2使用let:
var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6

eg2:里面的代码其实就相当于下面这段代码

var a = [];
{ let k;
    for (k = 0; k < 10; k++) {
      let i = k; //注意这里,每次循环都会创建一个新的i变量
      a[i] = function () {
        console.log(i);
      };
    }
}
a[6](); // 6

(5) let的暂时性死区:只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响,
死区范围:在let命令声明变量tmp之前,都属于变量tmp的“死区”。
下面这段代码中,声明了一个全局对象tmp,并在if语句体对tmp进行重新赋值。正常来说,该语句是正确的,但是添加了“let tmp”后,运行该程序,就会报错,显示“ReferenceError”。大多数人往往会忽略到第一个声明的tmp变量作用域包裹了第二个tmp

例1:
var tmp = 123;
if (true) {
  tmp = 'abc'; // ReferenceError
  let tmp;
}

例2:
function bar(x = y, y = 2) {//y还没有定义的时候就使用y
  return [x, y];
}

bar(); // 报错

例3:
// 不报错
var x = x;
// 报错
let x = x;

(6)块级作用域
ES6以前变量的作用域是函数范围,有时在函数内局部需要一些临时变量,因为没有块级作用域,所以就会将局部代码封装到IIEF中,这样达到了想要的效果又不引入多余的临时变量。而块作用域引入后,IIEF当然就不必要了!

function f(){
   ...
   swap(var_a,var_b);
   (function swap(a,b){
       var tmp;
       tmp = a;
       a = b;
       b=tmp;
   })(var_a,var_b);
}

如上面的代码,tmp被封装在IIFE中,就不会污染上层函数;而有块级作用域,就不用封装成IIEF,直接放到一个块级中就好。

{
// 块级作用域写法
{
  let tmp = ...;
  ...
}
}

(7)ES6对函数的改革

{
function add(x,y){return x+y};//这是es5中定义函数的写法

var add=(x,y)=>x+y;//es6中我们可以这么搞:
add(1,2);//3,正常运行

var fun1=x=>x+1;
fun1(3);//4,当参数为1个的时候 可以再简单一点,当然复杂函数还是需要括号与大括号的

var fun2=(...args)=>{
  for(let arg of args){
      console.log(arg)
  }
};
fun2(1,2,3);//1,2,3配合rest参数,fun2()里面的实参1,2,3会传到args被当做args的值,...args是es6的扩展运算符,会把参数fun2()传递的实参作为一个数组
}

上面我们提到了扩展运算符,es6扩展运算符,也就是... ,作用是将一个数组转为用逗号分隔的参数序列。
那么问题就来了,我们为啥要用这么奇怪的东东涅,当然因为它能大大提高我们的开发效率。因此,我们可别小看这三个点。下面我们来总结两条这三个小点的用途:
(1)复制数组:
在es5时代,要想复制数组,最容易想到的是通过for循环一个一个push,或者来个slice()的,现在有了扩展运算符,直接一步就能搞定:

var  arr = [1,2,3,4,5];
var copy = [...arr];

(2)将类似数组的对象转换为真正的数组
任何类似数组的对象可以用扩展运算符转换为真正的数组。比如:

var newNode= document.querySelectorAll('div');
var array = [...newNode];
Array.isArray(array)   //true
var str = 'hello';
var aStr = [...str];
Array.isArray(aStr)    //true

(8)关于es6函数声明的行为方式:
1允许在块级作用域内声明函数。
2函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
3同时,函数声明还会提升到所在的块级作用域的头部。

上面的三条规则只对 ES6 的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作let处理。

根据这三条规则,在浏览器的 ES6 环境中,块级作用域内声明的函数,行为类似于var声明的变量。

考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。如下

// 函数声明语句
{
  let a = 'secret';
  function f() {
    return a;
  }
}

// 函数表达式
{
  let a = 'secret';
  let f = function () {
    return a;
  };
}

另外,还有一个需要注意的地方。ES6 的块级作用域允许声明函数的规则,只在使用大括号的情况下成立,如果没有使用大括号,就会报错。

// 不报错
'use strict';
if (true) {
  function f() {}
}

// 报错
'use strict';
if (true)
  function f() {}

总结:

1、通过var定义的变量,作用域是整个封闭函数,是全域的 。通过let定义的变量,作用域是在块级或是子块中。

2、使用 let 声明的变量,在声明前无法使用,否则将会导致错误,并且不允许重复声明。

3、如果未在 let 语句中初始化您的变量,则将自动为其分配 JavaScript 值 undefined。

4、变量提升:不论var声明的变量处于当前作用域的第几行,都会提升到作用域的头部。
-var 声明的变量会被提升到作用域的顶部并初始化为undefined,而let声明的变量在作用域的顶部未被初始化

5、暂时性死区,在代码块内使用let命令声明变量之前,该变量都是不可用的,不受外部变量影响;

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容