node测试es6代码

{"name": "class1","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","build": "babel app.js --out-file bundle.js","script-name": "babel-node app.js"},"author": "","license": "ISC","devDependencies": {"babel-cli": "^6.26.0","babel-preset-env": "^1.7.0"}}

let
函数作用域,全局作用域。
[[scope]]
变量提升造成变量污染,解决这个问题通过,es5通过立即执行函数。
kiss原则 keep it simple ,stupid 保持简单和傻瓜式的,设计越简单越好,任何没有必要的复杂都要避免
不光编程用到kiss原则,生活中也会用到,在很多地方都能用到。
let块级作用域,举例:一个{}就是一个块,{}之间就是块级作用域
没有let时,只有全局作用域,函数作用域这两种,与GO、AO有关。let增加了新的作用域:块级作用域。
如果在全局中,全局也是一个块,类似于{全局},全局也被{}包裹一样。像一个一个嵌套的盒子,盒子套着盒子,盒子里面还有其它东西,在外面的盒子访问不到在里面盒子装的东西,里面盒子可以访问到外面盒子装的东西
块级作用域从形式上像{},像增加了一个{}
如果let声明在哪个{}中,相当于给这个括号中增加了块级作用域,如果{}之中没有let声明,那么这个{}中没有块级作用域。
如果方法function中没有let声明,那么function中没有块级作用域,但有函数作用域。虽然函数也是function a{},{}包裹起来的,但没有let声明就没有块级作用域。
总结:let所在的地方增加了以前没有的块级作用域。let所在的地方,才有块级作用域,块级作用域的范围由什么划分?由全局、{}、()来划分,let声明在它们中,它们中就有了块级作用域
let在全局,全局就是一个块
let在函数,在函数的那个{}下面,哪个{}下就有块级作用域
let在表达式(){}中,(){}中有块级作用域
if (1) {// 块级作用域}for (var i = 0; i < 10; i++) {// 块级作用域}for (; 1;) {// 块级作用域break;}{// 块级作用域}
不能重复
let同一作用域下不能重复声明,var可以
同一块级作用域下,let声明的变量,不允许重复声明
同一块级作用域下,let不允许声明已有变量(计算AO中的变量)
var GO、AO中提取,let不提取,其实是在let之前的,即使代码写在let后面,已有变量名,let不能重复定义
let在GO、AO中不会被提升,不会被提前提取,直接进入代码运行那个步骤,随着代码运行存入AO、GO中
示例解析:在全局作用域下,var可以重复声明不报错,后面覆盖前面
var a = 1;var a = 2;

示例解析:
在全局作用域下,let不可以重复声明,会报错
let a=1;let a=2;

node运行
示例解析:
函数内部let定义重复变量,出错
function test(){let a=1;let a=2;}


把一个let改成var依然报错
let声明,{}中有了块级作用域,块级作用域特性,let声明的变量不允许被重复声明
function test(){let a=1;var a=2;//Identifier 'a' has already been declared}test()
运行结果 node app.js运行
ctrl+shift+f10运行,与node运行结果一样

解析
function test(){/*AO={a:undefined->2}* AO先提取var a,不提取let a,变成var a=undefined与a=2*/let a=1;var a=2;//Identifier 'a' has already been declared}test()
同如下代码
function test(){/*AO={a:undefined->2}* AO先提取var a,不提取let a,变成var a=undefined与a=2,* a已经被定义了,let不能定义已有变量,var会被声明提升,不要只是看代码写的位置关系,代码前后* 要走预编译,AO,GO之后,再看代码关系,代码前后,写在后面的代码不一定运行在后面*/var a=undefined;let a=1;//Identifier 'a' has already been declareda=2;}test()
function test(a){let a=10;console.log(10);}test()
一样会出错
a在预编译时已经被定义了,let又重复定义a,也会报错
function test(a){{let a=10;console.log(a);//10}console.log(a);//undefined}test();
解析
function test(a){{let a=10;console.log(a);//10/*let声明,有了块级作用域1,这两个作用域声明的变量不互相影响,可以重复声明这不是同一个·作用域,可以重复声明变量a,*/}console.log(a);//undefined/*没有let声明,没有块级作用域,里面的a是形参,不受块级作用域1影响,因为在内部定义的变量,不能被外部的使用* 所以打印形参,为undefined*/}test();
function test(){let a=10;{console.log(a);//10}console.log(a);//10}test();
不能声明提升
let不会提升,会产生一个暂时性死区
声明提升
console.log(a);//undefinedvar a=10;/*Go={a:undefined->函数运行console->10}在预编译中,先提取函数声明,再运行代码*/
在这个例子中let之前会产生一个死区,let a之前都不能使用a,使用就会报错。写代码时,必须先定义,再使用。
let不存在函数提升,说明它不会在预编译的时候被提取,参与预编译,但不会被提取
console.log(a);// Cannot access 'a' before initializationlet a=10;

let a;// let a=undefined;console.log(a);//undefineda=10;
function test() {console.log(a);let a = 10;}test();/*报错,a未定义,再函数中,与在全局中一样*/
a被AO提升了,b不被提升,定义赋值为b时,b还是未定义状态
var a=a;console.log(a);//undefinedlet b=b;console.log(b)//Cannot access 'b' before initialization
let b;b=b;console.log(b)//undefined
let c;console.log(c);//undefined
function test(x=y,y=2){console.log(x,y);//ReferenceError: Cannot access 'y' before initialization}test();
这些例子,都要练习,这都是非常经典的例子。
这个依然是个死区,因为x赋值,赋值为y,这个时候y并,没有在之前被定义,之后才定义y=2。x=y,x调用y在y=2之前,x调用y是在死区调用的。,所以报错。
可以先不看x=y,先看y=2,有被定义,把y被定义前划分为死区,把死区圈起来,圈出来,看看x=y是不是在死区中调用。或者把不是死区的圈出来,看看x=y是否在不是死区中调用,是否在活区调用。
暂时性死区
function test(x=2,y=x){console.log(x,y);//2 2}test();
这样改就对了
console.log(typeof a);//undefined
console.log(typeof a);// Cannot access 'a' before initializationlet a;
let导致暂时性死区,导致typeof a报错,不像之前typeof是安全的,不会报错
这是个坑
let只能在当前作用域下生效
{let a=2;}console.log(a);// a is not defined
块级作用域定义的a,全局不能访问,不在同一个作用域下
if(1){let a=2;}console.log(a);// a is not defined
for (;1;){let a=1;}console.log(a);
死循环:不会报错,因为for代码一直执行,走不到下面的代码,因为nodejs是单核所以只会占用一个cpu,让它一直在那转,电脑也不会卡。如果在浏览器中一直运行,浏览器有可能就崩溃了。
注意循环到底有没有结束,什么时候结束
for (;1;){let a=1;break;}console.log(a);//a is not defined
for (let i = 0; i < 10; i++) {}console.log(i);// i is not defined
time48.25
var arr=[];for (var i = 0; i < 10; i++) {arr[i]=function (){console.log(i)}// arr[i]();//0-9}for (var i = 0; i < 10; i++) {arr[i]();//0-9}
知识都学过,怎么样用就有讲究了
time50.00
for(let i=0;i<10;i++){i='a';console.log(i);//a}
好像可以拿到i的值
i=a->i=a+1=NaN跳出循环
for(var i=0;i<10;i++){var i='a';console.log(i);//a}
多加 var i=’a’;没有影响,因为 var i=’a’;,var i被提升了到了全局
for(let i=0;i<10;i++){i='a';console.log(i);//a}
貌似在同一块级作用域下,其实不在
for(let i=0;i<10;i++){var i='a';/*Identifier 'i' has already been declared这是i=a语句报的错,不是console打印的*/console.log(i);}
for(let i=0;i<10;i++){/*let声明,产生块级作用域1*/{/*没有let声明,var声明,没有产生新的块级作用域,还是块级作用域1* 在块级作用域1里面,let重复定义了,var重复定义了*/var i='a';// Identifier 'i' has already been declaredconsole.log(i);}}
因为i已经被定义
for(let i=0;i<10;i++){let i='a';console.log(i);//10个a}
相当于新建了一个块级作用域,把之前{}内的内容包了起来,一切包了起来
for(let i=0;i<10;i++){{let i='a';console.log(i);// 10个a}}
而不是这样
for(let i=0;i<10;i++){{let i='a';}console.log(i);//0-9}
for (let i = 0; i < 10; i++) {/*块级作用域1,let声明产生块级作用域*/{let i = 'a';/*let声明,产生块级作用域2,i的两次定义不是在同一个块级作用域定义的*/console.log(i);// 10个a}console.log(i);//0-9}
相当于如下代码
if (1) {let a=1;{let a=10;/*这两个a,在内存里是不同的地方存储的,是不一样的值* 相当于新定义了一个a*/console.log(a);//10}}
babel转义成es5代码,如下
if (1) {var a = 1;{var _a = 10;/*又重新声明了一个_a,与a不一样*/console.log(_a); //10}}
if (1) {let a=1;{var a=10;//Identifier 'a' has already been declaredconsole.log(a);}}
这样写为什么报错?
var a=undefined;if (1) {let a=1;{a=10;console.log(a);//10}}
因为var参与预编译,被提升了,提升的过程中影响了上面的let a,提升到全局,也可以提升到,经过下面的变形
if (1) {var a = undefined;//SyntaxError: Identifier 'a' has already been declaredlet a = 1;{a = 10;console.log(a);//10}}
f (1) {let a=1;{/*没有let相当于更改了以前变量,更改之前变量,变成10*/a=10;console.log(a);//10}console.log(a);//10}
if (1) {let a = 1;/*let声明,产生块级作用域1*/{/*块级作用域2,console调用a,从最近的块级作用域取*/let a = 10;console.log(a);//10}console.log(a);//1}

var a=undefined;if (1) {let a=1;{a=10;var b=11;{let b=1;{var b=2;}}console.log(a);//10}console.log(a);//1}
只有里面的var b影响了外面的let b,里面的let b不影响外面的var b
总结
1.let本质上就是为了js增加了一个块级作用域;let所在的地方就是块级作用域所在的地方
if (1) {let a = 1;(function () {a = 10;console.log(a);//10})();console.log(a);//10}if (1) {let a = 1;(function () {let a = 10;console.log(a);//10})();console.log(a);//1}
块级作用域很像立即执行函数,但本身并不一样
函数声明
函数只能在最外层(全局),或者函数作用域中声明,这样是合法的
function test(){function test1(){}}
es5中不合法,在块级作用域中声明function是不合法的
es6合法了
{function test(){}}
es6合法
if (1) {function test() {}}try {function test() {}} catch (e) {function test1() {}}
不推荐,这不是友好的方式
因为虽然es5做出了兼容,但兼容性不好,不友好对于es5
建议这样写
try {var test1 = function () {}} catch (e) {var test1 = function () {}}
总结
不建议在块级作用域当中,用函数声明的方式来声明函数,而用函数表达式的方式
块级作用域没有返回值
if (1) {return a;}//错误 Unexpected token 'for'var a=for(;1;){return}{return}
没有参数让其接收
草案让其有返回值,但没有被采用
do{return}
块级作用域等于函数的立即调用?
错误,立即执行函数有返回值,块级作用域没有,块级作用域是作用域,另一个是函数执行,本质是两个完全不同的东西,虽然效果一样,部分效果一样。
虽然可以用函数立即执行模拟块级作用域,但它们确实不一样。
