一、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 = 123
console.log(a) // => 10
}
console.log(a) // => undefined
}
foo()
(2)不会声明提升
a.声明前引用,会报错(词法环境中,let和const声明的变量未初始化uninitialized)
let和const声明的变量存在词法环境中,预编译的时候,系统会注意let和const声明的变量,但是未初始化,这就是产生暂时性死区的原因。var声明的变量存在变量环境中的。
var a = a;
console.log(a) // => undefined
let 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 defined
node中,死循环不会卡死,会一直执行
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 = 1
console.log(i)
}
}
//转化成es5
if(1){
let i = 1;
{
let _i = 1
console.log(_i)
}
}
(6)es6兼容了在块级作用域中进行函数声明,但还是推荐函数表达式的方式。
(7)块级作用域没有返回值。和匿名立即执行函数有本质的区别,一个是函数,一个是作用域。