有些浏览器不兼容ES6+语法:
解决方案:ES6+ ——编译器(例如babel)——> ES5
而babel这种工具需要包管理工具,例如npm来安装。(这里包package代表代码块/功能块)。
而npm只能在node环境中实现;node也是能运行js代码的环境。
共享包:git工具,代码管理工具。
函数执行前预编译过程:AO,即生成函数上下文过程:
函数的参数相当于函数内部声明的变量;
解决变量污染的原则:KISS原则,keep it simple,stupid。
结论先行:let本质就是为了js增加一个块级作用域。
块级作用域形式上模样:{...}
同一作用域:块级作用域,函数作用域,全局作用域。
注:块级作用域是他们的子集。
重复声明的例子:
// Uncaught SyntaxError: Identifier 'a' has already been declared
let a = 1;
let a = 2;// Uncaught SyntaxError: Identifier 'a' has already been declared
function test(){let b = 1;var b = 2;
}
test();
函数中的参数相当于在函数内部声明的变量,违反let在同一作用域下不能重复声明的原则。
// Identifier 'a' has already been declared
function test(a){let a = 1;
}
test();
let不会声明提升,在let声明之前会产生暂时性死区,即无法访问这个变量。
TDZ:temporal DeaD Zone 暂时性死区
声明提升是在预编译的过程中,无论是在函数预编译还是全局预编译。
console.log(a); //undefined
var a = 10;// Uncaught ReferenceError: Cannot access 'b' before initialization
console.log(b);
let b = 2;// Uncaught ReferenceError: Cannot access 'b' before initialization
function test(){console.log(b);let b = 2;
}
test();
再举一个ES6暂时性死区问题:
// Uncaught ReferenceError: Cannot access 'y' before initialization
function test(x = y, y = 2){console.log(x,y);
}
test();
暂时性死区导致typeof不再安全:
console.log(typeof(a)); //undefined// Uncaught ReferenceError: Cannot access 'b' before initialization
console.log(typeof(b));
let b;
遵守了let在同一作用域下不可重复声明的原则,同时只在当前块级作用域之内生效。
function test(a){{let a = 10;}console.log(a);
}test();//undefined
let只能在当前作用域下生效:
// 例1:Uncaught ReferenceError: b is not defined
{let b = 1;
}
console.log(b);// Uncaught ReferenceError: a is not defined
if(1){let a = 1;
}
console.log(a);// 例2:死循环,永远不会报错
for(;1;){let a = 1;
}
console.log(a);
打印0-9:
var arr = [];
// 打印0-9
for(var i = 0; i < 10; i++){arr[i] = function(){console.log(i);}
}
for(var i = 0; i < 10; i++){arr[i]();
}
打印10个10:
var arr = [];
for(var i = 0; i < 10; i++){arr[i] = function(){console.log(i);}
}
for(var j = 0; j < 10; j++){arr[j]();
}
打印0-9,与上面打印10个10不同的地方在于,for循环中使用let声明变量,原因:
let创建了块级作用域,每次循环时内部的块级作用域都会去访问外层块级作用域中的变量i,而外层块级作用域中的变量i都不同,所以打印0-9
var arr = [];
for(let i = 0; i < 10; i++){arr[i] = function(){console.log(i);}
}
for(var j = 0; j < 10; j++){arr[j]();
}
打印报错原因:
var变量提升在作用域中是逐级往外提升的;也就是说var变量逐级提升的过程中,只要和let声明的变量处在同一个作用域内,就会报错。报错原因是:let在同一作用域下不可重复声明。
// 打印报错:Uncaught SyntaxError: Identifier 'i' has already been declared
for(let i = 0; i < 10; i++){var i = 'a';console.log(i);
}
打印了10个a:let定义的变量不在同一个作用域内,即使名字相同也不是同一个变量
for(let i = 0; i < 10; i++){let i = 'a';console.log(i);
}
相当于:
{let i = 0for(; i < 10;){{let i = 'a';console.log(i);}i++;}}
内层作用域可以更改外层作用域中的let声明的变量:
if(1){let a = 1;{a = 10;console.log(a); // 10}console.log(a); // 10
}
而let定义的变量不在同一个作用域内,即使名字相同也不是同一个变量:
if(1){let a = 1;{let a = 10console.log(a); // 10}console.log(a); // 1
}
补充:
ES5中函数声明的位置:顶层作用域,函数作用域。
ES6可以在块级作用域中声明函数,浏览器可以兼容,但不推荐这样使用——>在块级作用域中使用函数表达式代替函数声明。
if(i){function test(){}
}try {function test(){}
}catch(e){function test1(){}
}
解决方案:在块级作用域中使用函数表达式代替函数声明。
try {var test = function(){}
}catch(e){var test1 = function(){}
}
if(1){let a = 1;{(function(){a = 10;console.log(a); //10})();}console.log(a); //10
}
// ------------------------------------------------------------------
if(1){let a = 1;{(function(){var a = 10;console.log(a); //10})();}console.log(a);//1
}
// ------------------------------------------------------------------
if(1){let a = 1;{(function(){let a = 10;console.log(a); //10})();}console.log(a);//1}