一、Babel,a JavaScript compiler
    Babel 是一个工具链,将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 代码。
    Babel 构建在插件之上。使用现有的或者自己编写的插件可以组成一个转换管道。通过使用或创建一个preset即可轻松使用一组插件
    Babel的核心功能都在@babel/core模块中。
    @babel/cli允许我们在tereminal中使用Babel
    插件是小型的 JavaScript 程序,用于指导 Babel 如何对代码进行转换
    preset可以避免一个一个地添加插件,将插件组合起来使用,官方提供了一个名为’env‘的preset。
    pollify@babel/polyfill,用来emulate模拟js新特性(直接使用@babel/polyfill会污染全局,官方建议引用”core-js/stable”和”regenerator-runtime/runtime”)

    二、作用域
    作用域规定了当前能访问的变量范围。
    作用域是函数创建时,生成的js内部属性([[scope]]),确定了可以访问变量和方法的范围,保存着作用域链,而作用域链保存着各个函数的AO(函数执行期上下文)和GO(全局执行期上下文)。

    三、let
    (1)es5中,同一作用域内可以重复声明变量。es6中,不能用let重复声明变量
    重复声明的问题会出现在:
    (1)for循环中,用let声明迭代变量后,大括号内可以用let但不能用var声明同名变量,外部访问不了迭代变量。

    1. for(let i = 0; i < 10; i++){
    2. var i = 123 // 报错
    3. }
    4. console.log(i) // i is not defined

    (2)结构赋设置默认值时

    1. let {x = y, y} = { y : 123 }

    (3)函数内部,不能用let声明与形参同名变量,var可以重复声明。

    1. function foo (a){
    2. let a = 123
    3. }
    4. foo() // =>报错

    (4)使用函数参数默认值时,用到默认值的时候才会形成作用域

    1. function test(x = y, y){
    2. console.log(x)
    3. }
    4. test() // 报错,因为用到了默认值
    5. test(12) // => 12 不会报错,没有用到默认值,所以没有形成参数作用域且使用let声明x变量

    易错题

    1. let arr = []
    2. for(var i = 0; i < 10; i++){
    3. arr[i] = function(){
    4. console.log(i)
    5. }
    6. }
    7. for(var i = 0; i< 10; i++){
    8. arr[i]() // 0,1,2,3,4....9
    9. }
    10. // 因为每次重新声明了 i
    1. let 具有块级作用域 ,变量会保存在{ }块级作用域中,只在块级作用域中有效
    1. function foo (a){
    2. {
    3. let a = 123
    4. console.log(a) // => 10
    5. }
    6. console.log(a) // => undefined
    7. }
    8. foo()

    (2)不会声明提升
    a.声明前引用,会报错(词法环境中,let和const声明的变量未初始化uninitialized)
    let和const声明的变量存在词法环境中,预编译的时候,系统会注意let和const声明的变量,但是未初始化,这就是产生暂时性死区的原因。var声明的变量存在变量环境中的。

    1. var a = a;
    2. console.log(a) // => undefined
    3. let b = b;
    4. console.log(b) //报错 b is not defined

    b.给函数形参添加默认值也存在暂时性死区(产生了参数作用域,用let声明了形参)

    1. function test ( x = y, y = 2 ){
    2. console.log( x, y) // 报错
    3. }
    4. function ( x = 2, y = x ){
    5. console.log(x, y) // => 2, 2
    6. }
    1. c. typeof 判断 let 声明前的变量时,会报错。
    1. typeof a;
    2. let a; //报错 a is not defined
    1. 3let 只在当前作用域中有效
    1. if(1){
    2. let a = 123;
    3. }
    4. for(var i = 0; i < 10; i++){
    5. let a = 123
    6. }
    7. console.log(a) //这两种情况都会报错 a is not defined
    8. node中,死循环不会卡死,会一直执行
    9. for(;i;){
    10. let a = 123
    11. }
    12. console.log(a) //不会报错,因为会一直执行for循环的语句

    (4)for括号中,let声明的变量,记录在块级作用域中

    1. for(let a = 0; a < 10; a++){
    2. }
    3. console.log(a) //报错 a is not defined

    (5)for循环里面用let声明变量,小括号和大括号不是同一作用域,类似父子作用域

    1. for(var i = 0; i < 10; i++){
    2. i = 'a'
    3. console.log(i)
    4. }
    5. //只会打印一个a, 因为操作的是同一个变量,() 和 {}中属于同一个作用域。
    1. for(let i = 0; i< 10; i++){
    2. var i = '1' // 报错,
    3. console.log(i)
    4. }
    5. if(1){
    6. var i; // var 变量提升 到外部块级作用域?还是提升到全局作用域
    7. let i = 0;
    8. {
    9. let i = '1'
    10. }
    11. }
    12. for(let i = 0; i < 10; i++){
    13. let i = '1'
    14. console.log(i)
    15. } // 打'1'印 * 10
    16. 有两个块级作用域,小括号里面的块级作用域包含着内部块级作用域
    17. if(1){
    18. let i = 0;
    19. {
    20. let i = '1'
    21. }
    22. }
    1. if(1){
    2. let i = 1;
    3. {
    4. let i = 1
    5. console.log(i)
    6. }
    7. }
    8. //转化成es5
    9. if(1){
    10. let i = 1;
    11. {
    12. let _i = 1
    13. console.log(_i)
    14. }
    15. }

    (6)es6兼容了在块级作用域中进行函数声明,但还是推荐函数表达式的方式。
    (7)块级作用域没有返回值。和匿名立即执行函数有本质的区别,一个是函数,一个是作用域。