node测试es6代码

image.png

  1. {
  2. "name": "class1",
  3. "version": "1.0.0",
  4. "description": "",
  5. "main": "index.js",
  6. "scripts": {
  7. "test": "echo \"Error: no test specified\" && exit 1",
  8. "build": "babel app.js --out-file bundle.js",
  9. "script-name": "babel-node app.js"
  10. },
  11. "author": "",
  12. "license": "ISC",
  13. "devDependencies": {
  14. "babel-cli": "^6.26.0",
  15. "babel-preset-env": "^1.7.0"
  16. }
  17. }

image.png

let

函数作用域,全局作用域。
[[scope]]

变量提升造成变量污染,解决这个问题,es5通过立即执行函数,es6通过let就行了

kiss原则

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在表达式(){}中,(){}中有块级作用域

  1. if (1) {
  2. // 块级作用域
  3. }
  4. for (var i = 0; i < 10; i++) {
  5. // 块级作用域
  6. }
  7. for (; 1;) {
  8. // 块级作用域
  9. break;
  10. }
  11. {
  12. // 块级作用域
  13. }

let不能重复声明

let同一作用域下不能重复声明,var可以
同一块级作用域下,let声明的变量,不允许重复声明
同一块级作用域下,let不允许声明已有变量(计算AO中的变量)
var GO、AO中提取,let不提取,其实是在let之前的,即使var声明代码写在let后面,但它预编译时被提取,其实是在let前面的,已有变量名,let不能重复定义
let在GO、AO中不会被提升,不会被提前提取,直接进入代码运行那个步骤,随着代码运行存入AO、GO中

var在全局中,可以重复声明

示例解析:在全局作用域下,var可以重复声明不报错,后面覆盖前面,var声明的变量可以重复定义,并在预编译时被提取

  1. var a = 1;
  2. var a = 2;

image.png

let全局中,不能重复声明

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

  1. let a=1;
  2. let a=2;

image.png

node运行
image.png

let函数中,不能重复声明

示例解析:
函数内部let定义重复变量,出错

  1. function test(){
  2. let a=1;
  3. let a=2;
  4. }

image.png

image.png

let与var重复声明,冲突

把一个let改成var依然报错
let声明,{}中有了块级作用域,块级作用域特性,let声明的变量不允许被重复声明
image.png

  1. function test(){
  2. let a=1;
  3. var a=2;//Identifier 'a' has already been declared
  4. }
  5. test()

运行结果 node app.js运行
image.png
ctrl+shift+f10运行,与node运行结果一样

image.png
解析

  1. function test(){
  2. /*AO={a:undefined->2}
  3. * AO先提取var a,不提取let a,变成var a=undefined与a=2*/
  4. let a=1;
  5. var a=2;//Identifier 'a' has already been declared
  6. }
  7. test()

同如下代码

  1. function test(){
  2. /*AO={a:undefined->2}
  3. * AO先提取var a,不提取let a,变成var a=undefined与a=2,
  4. * a已经被定义了,let不能定义已有变量,var会被声明提升,不要只是看代码写的位置关系,代码前后
  5. * 要走预编译,AO,GO之后,再看代码关系,代码前后,写在后面的代码不一定运行在后面*/
  6. var a=undefined;
  7. let a=1;//Identifier 'a' has already been declared
  8. a=2;
  9. }
  10. test()

let与函数中形参重名,冲突

  1. function test(a){
  2. let a=10;
  3. console.log(10);
  4. }
  5. test()//Uncaught SyntaxError: Identifier 'a' has already been declared

一样会出错
a在预编译时已经被定义了,let又重复定义a,也会报错

  1. function test(a){
  2. {
  3. let a=10;
  4. console.log(a);//10
  5. }
  6. console.log(a);//undefined
  7. }
  8. test();

解析

  1. function test(a){
  2. {
  3. let a=10;
  4. console.log(a);//10
  5. /*let声明,有了块级作用域1,这两个作用域声明的变量不互相影响,可以重复声明
  6. 这不是同一个·作用域,可以重复声明变量a,*/
  7. }
  8. console.log(a);//undefined
  9. /*没有let声明,没有块级作用域,里面的a是形参,不受块级作用域1影响,因为在内部定义的变量,不能被外部的使用
  10. * 所以打印形参,为undefined*/
  11. }
  12. test();
  1. function test(){
  2. let a=10;
  3. {
  4. console.log(a);//10
  5. }
  6. console.log(a);//10
  7. }
  8. test();

不能声明提升

let不会提升,会产生一个暂时性死区

var会声明提升

声明提升
var会在预编译时被提前提取,提取但不赋值,之后再赋值

  1. console.log(a);//undefined
  2. var a=10;
  3. /*
  4. Go={
  5. a:undefined->函数运行console->10
  6. }
  7. 在预编译中,先提取函数声明,再运行代码
  8. */

let不能声明提升,会产生暂时性死区

在这个例子中let之前会产生一个死区,let a之前都不能使用a,使用就会报错。写代码时,必须先定义,再使用。
let不存在函数提升,说明它不会在预编译的时候被提取,参与预编译,但不会被提取

  1. console.log(a);// Cannot access 'a' before initialization
  2. let a=10;

image.png
上面代码不等同于下面代码

  1. let a;
  2. // let a=undefined;
  3. console.log(a);//undefined
  4. a=10;

let在函数中也不能声明提升

  1. function test() {
  2. console.log(a);
  3. let a = 10;
  4. }
  5. test();/*报错,a未定义,再函数中,与在全局中一样*/

let b=b的情况,会报错

a被AO提升了,b不被提升,定义赋值为b时,b还是未定义状态

  1. var a=a;
  2. console.log(a);//undefined
  3. let b=b;
  4. console.log(b)//Cannot access 'b' before initialization

不等价于以下代码

  1. let b;
  2. b=b;
  3. console.log(b)//undefined
  1. let c;
  2. console.log(c);//undefined

let与函数参数默认值的例子

  1. function test(x=y,y=2){
  2. console.log(x,y);//ReferenceError: Cannot access 'y' before initialization
  3. }
  4. test();

这些例子,都要练习,这都是非常经典的例子。
这个依然是个死区,因为x赋值,赋值为y,这个时候y并没有在之前被定义,之后才定义y=2。x=y,x调用y在y=2之前,x调用y是在死区调用的。,所以报错。
可以先不看x=y,先看y=2,有被定义,把y被定义前划分为死区,把死区圈起来,圈出来,看看x=y是不是在死区中调用。或者把不是死区的圈出来,看看x=y是否在不是死区中调用,是否在活区调用。
暂时性死区

  1. function test(x=2,y=x){
  2. console.log(x,y);//2 2
  3. }
  4. test();

这样改就对了

let会导致typeod可能报错

这里a其实是在全局中声明的,被AO提前提取

  1. console.log(typeof a);//undefined
  1. console.log(typeof a);// Cannot access 'a' before initialization
  2. let a;

let导致暂时性死区,导致typeof a报错,不像之前typeof是安全的,不会报错
这是个坑
如果a是用let声明的,并且在typeof使用前声明的,所以会报错

let只能在当前作用域下生效

外部得不到块级作用域内部的内容

  1. {
  2. let a=2;
  3. }
  4. console.log(a);// a is not defined

块级作用域定义的a,全局不能访问,不在同一个作用域下

  1. if(1){
  2. let a=2;
  3. }
  4. console.log(a);// a is not defined

死循环

  1. for (;1;){
  2. let a=1;
  3. }
  4. console.log(a);

死循环:不会报错,因为for代码一直执行,走不到下面的代码,因为nodejs是单核所以只会占用一个cpu,让它一直在那转,电脑也不会卡。如果在浏览器中一直运行,浏览器有可能就崩溃了。
注意循环到底有没有结束,什么时候结束

  1. for (;1;){
  2. let a=1;
  3. break;
  4. }
  5. console.log(a);//a is not defined

for表达式中的let变量,全局外部访问不到

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

for数组赋值(综合题目)

for var数组赋值

time48.25

  1. var arr=[];
  2. for (var i = 0; i < 10; i++) {
  3. arr[i]=function (){
  4. console.log(i)
  5. }
  6. // arr[i]();//0-9
  7. }
  8. for (var i = 0; i < 10; i++) {
  9. arr[i]();//0-9
  10. }

知识都学过,怎么样用就有讲究了

time50.00

for let var小题目

  1. for(let i=0;i<10;i++){
  2. i='a';
  3. console.log(i);//a
  4. }

好像可以拿到i的值
i=a->i=a+1=NaN跳出循环

  1. for(var i=0;i<10;i++){
  2. var i='a';
  3. console.log(i);//a
  4. }

多加 var i=’a’;没有影响,因为 var i=’a’;,var i被提升了到了全局

  1. for(let i=0;i<10;i++){
  2. i='a';
  3. console.log(i);//a
  4. }

貌似在同一块级作用域下,其实不在

  1. for(let i=0;i<10;i++){
  2. var i='a';
  3. /*
  4. Identifier 'i' has already been declared
  5. 这是i=a语句报的错,不是console打印的
  6. */
  7. console.log(i);
  8. }
  1. for(let i=0;i<10;i++){
  2. /*let声明,产生块级作用域1*/
  3. {
  4. /*没有let声明,var声明,没有产生新的块级作用域,还是块级作用域1
  5. * 在块级作用域1里面,重复定义了i*/
  6. var i='a';// Identifier 'i' has already been declared
  7. console.log(i);
  8. }
  9. }

因为i已经被定义

  1. for(let i=0;i<10;i++){
  2. let i='a';
  3. console.log(i);//10个a
  4. }

相当于新建了一个块级作用域,把之前{}内的内容包了起来,一切包了起来

  1. for(let i=0;i<10;i++){
  2. {
  3. let i='a';
  4. console.log(i);// 10个a
  5. }
  6. }

而不是这样

  1. for(let i=0;i<10;i++){
  2. {
  3. let i='a';
  4. }
  5. console.log(i);//0-9
  6. }


综合起来,如下代码

  1. for (let i = 0; i < 10; i++) {
  2. /*
  3. 块级作用域1,let声明产生块级作用域
  4. */
  5. {
  6. let i = 'a';
  7. /*let声明,产生块级作用域2,i的两次定义不是在同一个块级作用域定义的*/
  8. console.log(i);// 10个a
  9. }
  10. console.log(i);//0-9
  11. }

相当于如下代码

  1. if (1) {
  2. let a=1;
  3. {
  4. let a=10;
  5. /*这两个a,在内存里是不同的地方存储的,是不一样的值
  6. * 相当于新定义了一个a*/
  7. console.log(a);//10
  8. }
  9. }

babel转义成es5代码,如下

  1. if (1) {
  2. var a = 1;
  3. {
  4. var _a = 10;
  5. /*又重新声明了一个_a,与a不一样*/
  6. console.log(_a); //10
  7. }
  8. }

let受到var声明提升的过程的影响

  1. if (1) {
  2. let a=1;
  3. {
  4. var a=10;//Identifier 'a' has already been declared
  5. console.log(a);
  6. }
  7. }

这样写为什么报错?

  1. var a=undefined;
  2. if (1) {
  3. let a=1;
  4. {
  5. a=10;
  6. console.log(a);//10
  7. }
  8. }

因为var参与预编译,被提升了,提升的过程中影响了上面的let a,提升到全局,也可以提升到块级作用域的内部,经过下面的变形

  1. if (1) {
  2. var a = undefined;//SyntaxError: Identifier 'a' has already been declared
  3. let a = 1;
  4. {
  5. a = 10;
  6. console.log(a);//10
  7. }
  8. }
  1. f (1) {
  2. let a=1;
  3. {
  4. /*没有let相当于更改了以前变量,更改之前变量,变成10*/
  5. a=10;
  6. console.log(a);//10
  7. }
  8. console.log(a);//10
  9. }
  1. if (1) {
  2. let a = 1;
  3. /*let声明,产生块级作用域1*/
  4. {
  5. /*块级作用域2,console调用a,从最近的块级作用域取*/
  6. let a = 10;
  7. console.log(a);//10
  8. }
  9. console.log(a);//1
  10. }

image.png

  1. var a=undefined;
  2. if (1) {
  3. let a=1;
  4. {
  5. a=10;
  6. var b=11;
  7. {
  8. let b=1;
  9. {
  10. var b=2;
  11. }
  12. }
  13. console.log(a);//10
  14. }
  15. console.log(a);//1
  16. }

只有里面的var b影响了外面的let b,里面的let b不影响外面的var b

总结

1.let本质上就是为了js增加了一个块级作用域;let所在的地方就是块级作用域所在的地方

  1. if (1) {
  2. let a = 1;
  3. (function () {
  4. a = 10;
  5. console.log(a);//10
  6. })();
  7. console.log(a);//10
  8. }
  9. if (1) {
  10. let a = 1;
  11. (function () {
  12. let a = 10;
  13. console.log(a);//10
  14. })();
  15. console.log(a);//1
  16. }

块级作用域很像立即执行函数,但本身并不一样

函数声明:建议用函数表达式的方式

函数只能在最外层(全局),或者函数作用域中声明,这样是合法的

  1. function test(){
  2. function test1(){
  3. }
  4. }

es5中不合法,在块级作用域中声明function是不合法的
es6合法了

  1. {
  2. function test(){
  3. }
  4. }

es6合法

  1. if (1) {
  2. function test() {
  3. }
  4. }
  5. try {
  6. function test() {
  7. }
  8. } catch (e) {
  9. function test1() {
  10. }
  11. }

不推荐,这不是友好的方式
因为虽然es5做出了兼容,但兼容性不好,不友好对于es5

建议这样写,建议用函数表达式的方式

  1. try {
  2. var test1 = function () {
  3. }
  4. } catch (e) {
  5. var test1 = function () {
  6. }
  7. }

总结

不建议在块级作用域当中,用函数声明的方式来声明函数,而用函数表达式的方式

块级作用域没有返回值

  1. if (1) {
  2. return a;
  3. }
  4. //错误 Unexpected token 'for'
  5. var a=for(;1;){
  6. return
  7. }
  8. {
  9. return
  10. }

没有参数让其接收

草案让其有返回值,但没有被采用

  1. do{
  2. return
  3. }

块级作用域等于函数的立即调用?
错误,立即执行函数有返回值,块级作用域没有,块级作用域是作用域,另一个是函数执行,本质是两个完全不同的东西,虽然效果一样,部分效果一样。
虽然可以用函数立即执行模拟块级作用域,但它们确实不一样。