一、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声明同名变量,外部访问不了迭代变量。
for(let i = 0; i < 10; i++){var i = 123 // 报错}console.log(i) // i is not defined
(2)结构赋设置默认值时
let {x = y, y} = { y : 123 }
(3)函数内部,不能用let声明与形参同名变量,var可以重复声明。
function foo (a){let a = 123}foo() // =>报错
(4)使用函数参数默认值时,用到默认值的时候才会形成作用域
function test(x = y, y){console.log(x)}test() // 报错,因为用到了默认值test(12) // => 12 不会报错,没有用到默认值,所以没有形成参数作用域且使用let声明x变量
易错题
let arr = []for(var i = 0; i < 10; i++){arr[i] = function(){console.log(i)}}for(var i = 0; i< 10; i++){arr[i]() // 0,1,2,3,4....9}// 因为每次重新声明了 i
let 具有块级作用域 ,变量会保存在{ }块级作用域中,只在块级作用域中有效
function foo (a){{let a = 123console.log(a) // => 10}console.log(a) // => undefined}foo()
(2)不会声明提升
a.声明前引用,会报错(词法环境中,let和const声明的变量未初始化uninitialized)
let和const声明的变量存在词法环境中,预编译的时候,系统会注意let和const声明的变量,但是未初始化,这就是产生暂时性死区的原因。var声明的变量存在变量环境中的。
var a = a;console.log(a) // => undefinedlet b = b;console.log(b) //报错 b is not defined
b.给函数形参添加默认值也存在暂时性死区(产生了参数作用域,用let声明了形参)
function test ( x = y, y = 2 ){console.log( x, y) // 报错}function ( x = 2, y = x ){console.log(x, y) // => 2, 2}
c. 用typeof 判断 let 声明前的变量时,会报错。
typeof a;let a; //报错 a is not defined
(3)let 只在当前作用域中有效
if(1){let a = 123;}for(var i = 0; i < 10; i++){let a = 123}console.log(a) //这两种情况都会报错 a is not definednode中,死循环不会卡死,会一直执行for(;i;){let a = 123}console.log(a) //不会报错,因为会一直执行for循环的语句
(4)for括号中,let声明的变量,记录在块级作用域中
for(let a = 0; a < 10; a++){}console.log(a) //报错 a is not defined
(5)for循环里面用let声明变量,小括号和大括号不是同一作用域,类似父子作用域
for(var i = 0; i < 10; i++){i = 'a'console.log(i)}//只会打印一个a, 因为操作的是同一个变量,() 和 {}中属于同一个作用域。
for(let i = 0; i< 10; i++){var i = '1' // 报错,console.log(i)}if(1){var i; // var 变量提升 到外部块级作用域?还是提升到全局作用域let i = 0;{let i = '1'}}for(let i = 0; i < 10; i++){let i = '1'console.log(i)} // 打'1'印 * 10有两个块级作用域,小括号里面的块级作用域包含着内部块级作用域if(1){let i = 0;{let i = '1'}}
if(1){let i = 1;{let i = 1console.log(i)}}//转化成es5if(1){let i = 1;{let _i = 1console.log(_i)}}
(6)es6兼容了在块级作用域中进行函数声明,但还是推荐函数表达式的方式。
(7)块级作用域没有返回值。和匿名立即执行函数有本质的区别,一个是函数,一个是作用域。
