ES6 笔记

ECMAScript 6

一、块级作用域: let,const

1.1 基本用法

const: 声明常量,在声明时必须被赋值,一般大写命名

let : 声明变量,所声明的变量,只在let命令所在的代码块内有效

const的应用场景

  1. 函数中不变的系数,例如 y=kx+b中的k和b
  2. 系统中固定都参数,比如数据库的用户,密码,库名,表名,URL地址等
  3. 定义一个函数
  4. 定义一个js对象
  5. 声明对象:对象不能再换,但值可以修改

当需要修改时,使用let

let声明的变量只在它所在的代码块有效
例:

    {
        var a = 1; //使用var,将变量提升至最高0hhrg
        let b = 2; //只在代码块中有效
    }
输出:
    a // ReferenceError: a is not defined
    b // 2
        

var命令会发生'变量提升'现象

let和coust则不会发生

1.2 不存在变量提升

var命令会发生"变量提升"现象,值为undefined,

为纠正这种现象,let改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。

1.3 暂时性死区(temporal dead zone,简称 TDZ)

JavaScript引擎在扫描代码时发现变量声明时

  1. 如果是var, 则会提升至html
  2. 如果是let&&coust,则会将提至暂时性死区中

只有执行过变量声明语句后,变量才会从TDZ中移出后才能正常访问;
例:

    var tmp = 123;
    if(true){
    //未声明前就被使用
        tmp = 66; // 报错:ReferenceError
        let tmp;
    }

1.4 不允许重复声明

不允许在相同作用域中重复声明同一个变量

面试题:let和coust是什么

  • 块级作用域
  • 不会发生变量提升现象
  • 有暂时性死区

解构赋值

1.1 数组的解构赋值

数组本身就是个对象

    以前写法:
        let a = 1;
        let b = 2;
        let c = 3;
    在ES6中允许写成:
        let [a,b,c] = [1,2,3];
        
        let [a,,c] = [1,2,3]
        a//1
        c//3
            //更为简便,方便
        对于Set结构,也可以使用数组的解构赋值
        let [x,y,z] = new Set(['a','b','c']);
        //字符串
        let [a,b,c,d,e] = 'hello';
        a//h,
        b//e
        c//l
        d//l
        e//o
        

当解构不成功的时候,变量值变为undefined
如果等号的右边不为数组,将报错

例:

    let [foo] = null;
    let [foo] = 1;
    let [foo] = {};
    let [foo] = undefined;
        

1.2 对象的解构赋值

    let {foo,bar} = {foo:'aa',bar:'xx'};
    //如果没有对应的属性名吗,则结构失败
    //变为undefined
    
    
    //对象的解构赋值,可以将现存在对象的方法,赋值到变量
    let {log} = console;
    log('hello');
    let {x=3} = {}; //ES6思维
    -------------------
    var {x:x} = {}; //对象结构
    if(x == undefined){ //条件判断给默认值 可以改为if(!x)代替
        x = 3;
    }
    -------------------
    //传统思维
    var myObj = {}; //声明一个目标对象
    var x = myObj.x; //没有对象解构,传统通过访问属性赋值给一个变量
    if(x == undefined){
        x = 3;
    }
    

1.3函数参数的解构赋值

    const myArray = [1,2,3];
    const myFun = function (item){
        console.log('hi:'+item);
    }
    
    myArray.map(myFun); //myFun执行几次取决于myArray中的位数
    
    //这个for循坏等效于上面这串代码
    for(let i=0 ;i<myArray.length ;i++){
        myFun();//运行几次取决于myArray的长度
        
        myFun(myArray[i]);//遍历出数组myArray的内容
    }
    

例:

   const myArray = [{age:17},{age:18},{age:19},{age:20}] 
   
   let newArray = myArray.map( function({age})){
       return age * 2 ;
   })
   
   //map()   作用:1. 2.创建一个新数组
   console.log( newArray );
  1. 是一个数组,而且是数组中有数组(数组的嵌套). [[1,2],[3,4]]
  2. map等于对代码段function进行了for遍历,数组中有2个元素,代码段就会执行2次
  3. 代码段中的function参数,传值的内容,上述数组中的元素
  4. 如果传值的变量本身就是一个数组或对象,可以进行进一步的解构
  5. 这个代码段对象中return用来干嘛,用于构造出一个全选的数组

1.4 箭头函数

1.5 this

1.1 this的引用

根层调用this,指向最根层的window对象

    const student = {
	name:'十五',
	sex:'很好',
	play(){
	console.log(this);  
 }
}

student.play(); //函数中this指向跟调用者一样 ,student,this不固定
let {play} = student;
play();  //根层调用它,window

实例:


const myClass = {
	no:'S4155',
	stuList:[
	{name:'十五','age':18,play(){console.log(this)}},
	{name:'十六','age':17,play() => {console.log(this)}}
	//箭头函数的this,指向与它的上一级同等,window
	]
}

myClass.stuList[0].play();  //调用者是谁,this就指向谁
		//调用者为myClass.stuList[0],就是'十五'这条数据
		
let {stuList:[{play}]} = myClass ; //解构赋值
play();	//this指向window

原始数据类型 Symbol

-第七种数据类型

-表示独一无二的值

其他数据类型:

  • nudefined、null
  • Boolean、String
  • Number、Object
  • BigInt

Set与Map数据结构

Set()是一个构造函数,内部封装好的
用来生成Set()数据结构,类似数组,但其中的成员是唯一的,没有重复的值.

    let a = new Set();
    //通过forEach遍历
    [1,2,3,4].forEach(x => a.add(x));

    console.log(a);

Set函数可以接收一个数组作为参数,用来初始化

    let a = new Set([1,2,3,4,4]);
    [...a]  //[1,2,3,4]
    //通过...来展开

Set()实例操作方法:

Set.prototype.add(value);//添加某个值,返回Set结构本身
Set.prototype.delete(value);//删除某个值,返回一个布尔值
Set.prototype.has(value);//返回一个布尔值,表明该值是否为Set的成员
Set.prototype.clear();//清除全部成员,无返回值

a.add(x);
a.delete(x);

使用Array.from()方法可以将Set结构转化为数组结构

for...of循环

语法:

    for(item of arr){
        console.log(item);
    }
    
    

例子:

    const arr2 = [{name:'十五'},{name:'十六'},{name:'十七'}]
    //使用for...fo循环
    for( let {name}  of arr2){
	console.log(name); //十五,十六,十七 
    }
    
    //forEach
    arr2.forEach(el => console.log(el.name));//十五,十六,十七 
    
    //不使用箭头函数,本质
    arr2.forEach(
        //el -> 代表遍历后储存的数据
        function (el){
            console.log(el.name)
            //十五,十六,十七 
        }
    )
    

Class 的语法与继承

ES5 模仿类的写法

//  不要看成是函数
    //声明一个类
    function name(x,y){
        this.x = x;
        this.y = y;
    }
    //把方法写在外层
    name.prototype.run = function (){
        console.log(this.x + this.y);
    }
    
    
let name2 = new name(15,15); //创建一个实例
console.log(name2);
name2.run();  //30

ES6的Class语法糖:Class写法

    class name{
        constructor(x,y){
            this.x = x;
            this.y = y;
        }
        //将方法卸载
        run(){
            return this.x + this.y ;
        }
    }

ES6的Class不需要箭头函数,也不存在

Module 模块

ES5 :

    //CommonJs模块
    var { stat, exists, readfile } = require('fs');

    //两者等效,只是时代更迭,所以使用ES6模块写法

    //es6模块
    import { stat,exists, readfile } from 'fs';
    import fs form 'fs';
    

node.js

//页面大
var e = require('element-ui');

//页面还是很大
var {Button} = require('element-ui');

node.js --> 拿代码,以及导入的代码,进行分析,重新打包,给回一个按需的,解构的
	--> 压缩的全选的代码返回(页面就变小,加载速度变快)

//ES6之前模块化处理 -->
commonJS.js与AMD

//CommonJS
  var math = require('math');  
  math.add(2,3);// 需要等math.js加载完毕
  
  -----
  //AMD
    //当加载完毕后,执行一段代码
  require('math',function(){
      math.add(2,3);
  });
  
  //需要下载require.js和curl.js

require.js使用

    创建一个html文件
    将下载的require.js文件加入
    再创建一个自己的js文件
    //在html中引入require.js和自己的js文件
    ` <script src="require.js"  data-main="main"></script>`

JavaScript modules 模块

最新的浏览器开始原生支持模块功能了

使用模块依赖于import和export

当创建一个模块文件时,我们可以将后缀由.js改为.mjs,来分辨到底是模块文件还是常规文件

    //用来指示引入的模块
    <script type = "module">
    
    </script>
-----------------------------------------------
    例:
    //main.js文件
    <script>
        const a = 1;
        const b = 2;
        export default {a as a1}
        //当导出多个时,将不再使用default
        //使用 as 来进行别名
        export {a as a1,b as b1}
    </script>
    -------------
    //main.html文件
    <script type = "module">
    import a1 from 'main.js的路径'
    console.log(a1);
    
    //将import输入的变量是可读的,不可改变
    //对其重新赋值将会报错
    //但如果是一个对象,改写属性是允许的
    //import会提升,首先执行,并且是静态执行,不能在里面进行运算等一系列凑在哦
    </script>
    

ES6模块化测试必须在服务器上(tomcat)测试,如果本地浏览器会报错.(或者使用编辑器)

具体的内容可访问
JavaScript modules 模块

Promise

Promise是一个异步编程的解决方案,有三种状态:
pending(进行中),fulfilled(已成功),rejected(已失败),状态一旦发生改变就不能再次改变

Promise的不足:1.Promise的链式调用可以让代码更直观,但还是存在冗余

2.无法取消,一旦新建就会执行

3.不设置回调函数,Promise内部抛出的错误,不会反应到外部

4.当处于pending状态时,无法得知进展阶段

  • 主线程
  • 微任务
  • 宏任务

当主线程执行完后,下发给微任务,最后加载宏任务。

一个异步加载图片的例子


    <div id='aa'></div>
<script>

        function loadImg( imgSrc,pass,error ){
            console.log('打开洗衣机');
            //创建一个图像实例
            let image = new Image();
            //图像的地址等于传参的imgSrc
            image.src = imgSrc;
            //加载事件
            image.onload = () => {

                pass(image);
            };
            //当失败时,将失败输出给参数error来完成
            image.onerror = error;
            console.log('按开关');
        }
        

        //调用方法 ,参数为imgSrc、pass、error
        loadImg('../../img/baidu.jpg',(image) => {
            //image 输出的是一个带有路径的img标签
            //将img节点添加到div父节点的最后一个节点上
            let img = document.getElementById('aa').appendChild(image);
            console.log('洗成功了')
        },() => {
                console.log('失败');
            });
    </script>

关于执行

    setTimeout( ()=>{
	    console.log('最后的宏任务');  //宏任务,第三步
    },3000)                         //定时器,在微任务结束3秒后开始执行

    let a = new Promise( (resolve,reject) =>{
	          resolve('成功了');       //主线程,第一步
	           //当参数不同,那么触发的内容也不同
    }).then(
	(resolve)=>{ console.log(resolve+'可以吃饭')},  //微任务,第二步
	(reject) =>{ console.log(reject+'不可以吃饭')}//微任务,第二步
    )
    console.log('在吃饭吗');  //主线程,第一步

状态中转

    var Prom = new Promise((resolve,reject)=>{
        resolve('主线程1,任务没人接收');
    })
    
    var Prom2 = new Promise((resolve,reject)=>{
        console.log('主线程2,让微任务去做主线程1的事');//1.
        resolve(Prom);  //委托主线程2的微任务帮忙
    }).then(
        resolve=>{console.log(resolve+':我来接收了')},//2
        reject=>{console.log('失败了')}
    )
    
    输出://1.主线程2,让微任务去做主线程1的事
        //2.主线程1,任务没人接收:我来接收了
    

套娃操作

    new Promise((resolve,reject)=>{
        resolve('成功了');//主线程1
    }).then(
    resolve=>{return new Promise(
    (resolve2,reject2)=>{
        resolve2('成功了2')  //主线程2
    }
    )},
    reject=>{}
    ).then(
        resolve=>{console.log(resolve)}, 
        //输出:'成功了2',执行第二个Promise
        reject=>{console.log(reject)}
    )
    //请注意: 微任务是通过return来传值的

carth():捕获错误

    

Promise的语法糖:async...await

例:

   async function k1(){
       let text = await '123'  //await 相当于 then
       console.log(text);  //text
   } 
   //语法糖的根本只是为了简洁方便,最底层还是Promise
   //将上述转译为下
   ∧
   
   ∨
   //原生写法
   new Promise((resolve,reject)=>{
       resolve('123');
   }).then(
            resolve =>console.log(resolve),
            reject => console.log(reject)
   )
   

利用async...await做的延时显示

//声明一个数组
let arr = [1,2,3]

function k1(){
    return new Promise((resolve)=>{
             setTimeout(()=>{resolve()},1500)
      })               
}
//遍历数组
//使用async..await
async function k2(){

for(let arr2 of arr){

       console.log(arr2);
       await k1()
     }

}
       k2();
    //实现了一个延时逐个显示的延时器

原理解析

式子1. let a = 999;
式子2. let a2 = await 999;

第一个: 返回一个Promise
    原理Promise写法:
        new Promise(resolve=>{
            resolve(999)
        })
        .then(a=>{console.log(a)})
        
第二个:
    写法:
    async function k(){
     let a2 = await 999;  //局长与处长
                    //返回的是局长发出的通知,不是局长的肉体
                    //等待:等局长吃饱,局长发通知
                    //等号左边存储局长通知的内容:999
     console.log(a2); 
     }
k()

杂类

ES6多行字符串与模板字符串

    console.log(`多行
            字符
            串`
    );
    
    //符号: `  `
------------------------
与+号连接同理
var text1 = '小明';
var text2 = 20;
console.log(`你好,${text1},你今年${text2}岁了`);
//输出: 你好,小明,你今年20岁了
posted @ 2022-03-23 20:02  十五十五  阅读(45)  评论(0编辑  收藏  举报