ES6学习笔记

2,235 阅读14分钟

本人小白,欢迎指正

一、变量let和const

var:

  1. 可以重复声明
  2. 可以进行变量提升(即将声明提升到最前面)

let:

  1. 不可以重复声明
  2. 块级作用域
  3. 不可以变量提升

const:

  1. 不可以重复声明
  2. 块级作用域
  3. 声明后不可以进行修改
  4. 声明时必须初始化
  5. const声明的数组内容可以被修改,所以常规使用const进行数组变量的声明

二、解构赋值

1.什么是解构?:es6允许按照一定的模式,从数组和对象中提取值,对变量进行赋值,这被称为解构

2.数组解构赋值:

语法:
let [a,b,c] = [1,2,3];

console.log(a,b,c);

3.对象解构赋值:

语法:
let{a,b} = {
        a:'aa',
        b:'bb'
};

console.log(a,b);
顺序:数据解构按照对应位置关系,但是对象解构变量没有顺序,变量必须与属性同名,才能解构成功。
注意:let和const声明的变量不可以进行解构赋值!

4.字符串的解构赋值:

语法:
 let[a,b,c,d] = 'hello';
 console.log(a,b,c,d);//h e l l

5.数值和布尔值的解构赋值:

6.函数的解构赋值:

语法:
 function fun([x,y]){
 console.log(x+y);
 }

 fun([1,2]);//实参

7.解构的用途:

  1. 交换变量的值
  2. 从函数返回多个值(这样就可以快速调用一些数据)
  3. 函数传参
  4. 提取json数据(解构对提取json尤其有用)
  5. 函数参数默认值(es6允许函数的参数设置默认值)

8.函数默认初始值:

一般用法:(直接将默认值写在形参之后)
function fun(x,y ='world'){
       console.log(x,y);
 }

与解构配合使用:

function fun({x,y=5}={}){
       console.log(x,y);
}
注意:
1. 函数的length属性是函数的形参个数!
2. 一般带有默认值得参数要放在最后!(潜规则)

三、模板字符串

1.JavaScript写法:

 'He is <b>'+person.name+'</b>'+'and we wish to know his'+person.age+' . That is all.'

2.模板字符串写法:

`He is <b>${person.name}</b> and we wish know his ${person.age} . That is all.`

这种写法减免了很多的繁杂的工作!

如果需要使用' ` ',则可以进行转义!

当然,模板字符串也可以不引入变量,可以简单的使用!

四、对象的简化写法

1.ES6允许在大括号里面,直接写入变量和函数,作为对象的属性和方法在Vue中经常使用,这样写会使得编写更加的简洁!

五、箭头函数

1.ES6允许使用「箭头」(=>)定义函数

声明函数的两种方法:
 let fn = function(){
 }

 let fn = (a,b) => {
 return a+b;
 }

2.this是静态的,this始终指向函数声明时所在作用域下的this的值

3.箭头函数的this值是静态的,始终指向函数声明时所在作用域下的this的值

例如:
 //常规声明
 function getName() {
        console.log(this.name);
 }
 //箭头函数
 let getName2 = () => {
        console.log(this.name); 
 }
 window.name = '周师扬';
        const school = {
        name: 'zsy'
 }
 
 getName();//周师扬
 getName2();//周师扬
 getName.call(school);//zsy
 getName2.call(school);//周师扬

4.箭头函数不能作为一个构造函数实例化对象!

5.箭头函数不能使用arguments变量:

典型错误用法:
 let fn = () =>{
 console.log(arguments)
 }

 fn(1,2,3);//将会报错,箭头函数不支持arguments参数

6.箭头函数的简写:

  1. 省略小括号: 当形参有且只有一个的时候
  2. 省略花括号: 当代码体只有一条语句的时候

7.箭头函数适合于与函数的this无关的的回调,例如:定时器,数组等的方法回调不适合于与函数的this有关的的方法的回调,建议使用function( );不适合对象内方法的定义,否则作用域可能会出现问题

六、ES6的rest参数

1.ES5中使用arguments参数进行获取函数的实参

例如:
 function fn(){
        console.log(arguments);//返回的是Object对象
 }

2.ES5中使用rest参数进行获取函数的实参

例如:
 function fn(…args){
        console.log(args);//返回的是Array对象,更加便于对函数实参的处理
 }
更加高级的用例:
 function fn(a,b,…args){//args要放到后面
        console.log(a);//1
        console.log(b);//2
        console.log(args);//3 4 5 6
 }

 fn(1,2,3,4,5,6);

七、扩展运算符

1.「 … 」能将数组转化为用逗号分隔的「参数序列」

基本用法:
 const TFboys = ['王源','易烊千玺','王俊凯'];
 function show(){
        console.log(arguments);
 }

 show(…TFboys);//返回的是=>‘王源’,’易烊千玺’,’王俊凯’的字符序列

2.扩展运算符用于数组的合并

ES5用法:
 const kuaizi = ['肖央','王太利'];
 const fenghuang = ['曾毅','玲花'];
 const zuixuan = kuaizi.concat(fenghuang);
ES6用法:
 const zuixuan = […fenghuang,…kuaizi];//使用扩展运算符

3.扩展运算符用于数组的克隆

 const arr1 = ['z','s','y'];
 const arr2 = […arr1];//使用...进行clone

4.将伪数组转化成为真正的数组

 const divs = document.querySelectorAll('div');
 const divarr = [..divs];//已经转化为了真正的数组

八、Symbol

Symbol是一种标识符,是一种类型,表示独一无二的值

1.Symbol简介:

  1. Symbol的值是唯一的,用来解决命名冲突的问题
  2. Symbol的值不能与其他数据进行运算
  3. Symbol定义的对象属性不能使用for…in...进行循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名

2.创建Symbol的两种方式:

  1. 直接使用Symbol进行创建:
 let s1 = Symbol('zsy');
 let s2 = Symbol('zsy');
 console.log(s1 === s2);//false,注意这里是不相等的!
  1. 使用Symbol.for进行创建
 let s1 = Symbol.for('zsy');
 let s2 = Symbol.for('zsy');
 console.log(s1 === s2);//true,这样就是相等的了!

3. Symbol的使用

使用Symbol安全的添加methods(function):
 let game = {}
 let methods = {
        up:Symbol(),
        down:Symbol()
 }
 game[method.up] = function(){
        console.log('1');
 }
 game[method.down] = function(){
        console.log('1');
 }
在另一种情况下添加methods(内部):
let youxi = {
       name:'狼人杀',
       [Symbol('say')]:function(){
               console.log('I can say!');
       }
}

4. Symbol的内置方法,可以自己查看文档

九、迭代器

1.for…in…:遍历返回的是键名~~~for…of…:遍历返回的是键值

2.迭代器的工作原理

  1. 创建一个指针对象,指向当前数据结构的起始位置
  2. 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
  3. 接下来不断使用next方法,指针不断向后移动直到指向最后一个数据成员
  4. 每调用一次方法返回一个包含value和done属性的对象(done代表是否完,为一个布尔值,如果遍历完成则为ture,否则为false)

3.注意:要自定义遍历数据的时候,要想到迭代器!

自定义遍历数据代码实例:
 const stu = {
        name: "zsy",
        stus: [
                'xiaoming',
                'xiaoning',
                'xiaotian',
                'knight'
            ],
        [Symbol.iterator]() {//必须要有iterator对象
                let index = 0;
                let _this = this;//保存this
                return {
                        next: function() {
                        if (index < _this.stus.length) {
                                const result = {
                                        value: _this.stus[index],
                                        done: false
                                };
                                index++;
                                return result;
                        } 
                        else {
                                return {
                                        value: undefined,
                                        done: true
                                };
                        }
                 }
        }
        }
 }
 
 for (let v of stu) {
        console.log(v);
 }

十、生成器

1.生成器是一个特殊的函数,常用于异步编程

初识生成器函数:
 function * gen() {//生成器函数的特殊写法,注意拥有*
        console.log('hello zsy!');
 }

 let ite = gen();
 // console.log(ite);//这是一个错误的写法,这样并不能运行生成器函数
 ite.next();//这是一个正确的写法,执行语句

2.生成器函数中允许出现yield关键字(yield关键字:用于分隔代码块,每次执行两个yield中的代码)

示例:
 function * gen() {
        console.log('1');
        yield 'I am 1';
        console.log('2');
        yield 'I am 2';
        console.log('3');
        yield 'I am 3';
        console.log('4');
 }

 let ite = gen();
 ite.next();//1
 ite.next();//2
 ite.next();//3
 ite.next();//4

3.生成器函数可以使用for…of…进行遍历

 function * gen() {
        yield 'I am 1';
        yield 'I am 2';
        yield 'I am 3';
 }

 for(let v of gen()){
        console.log(v);
 }

 //输出的结果为yield后面的语句运行的结果
 //I’m 1
 //I’m 2
 //I’m 3

4.next函数可以传参,传的参数作为下一个yield后面的值,可以打印查看。

5.生成器函数的实例:(异步编程:有助于避免回调地狱(缩进向前延伸导致超出编辑区域不利于阅读和维护))

(使用定时器实现)
 function one(){
        setTimeout(()=>{
                console.log(111);
                ite.next();
        },1000}
 }

 function two(){
        setTimeout(()=>{
                console.log(222);
                ite.next();
        },2000}
 }

 function three(){
        setTimeout(()=>{
                console.log(333);
                ite.next();
        },3000}
 }

 function *gen(){
        yield one();
        yield two();
        yield three();
 }

 let ite = gen();
 ite.next();//这样就实现了异步输出
(实现获取数据的模拟过程)
(异步符合现实生活)
 function getUsers(){
        setTimeout(()=>{
                let data = '用户数据';
                ite.next(data);
        },1000)
 }
 function getOrders(){
        setTimeout(()=>{
                let data = '订单数据';
                ite.next(data);
        },1000)
 }

 function getGoods(){
        setTimeout(()=>{
                let data = '商品数据';
                ite.next(data);
        },1000)
 }

 function * gen(){
        let users = yield getUsers();
        console.log(users); 
        let orders = yield getOrders();
        console.log(orders);
        let goods = yield getGoods();
        console.log(goods);
 }

 let ite = gen();
 ite.next();

十一、ES6中的promise

1.promise是ES6引出的新的异步编程的解决方案,语法上promise是一个构造函数,用来封装异步操作并且可以获取其成功或失败的结果

2.简单的promise用例

 const p = new Promise(function(resolve,reject){//常用resolve和reject
        setTimeout(function(){
                let data = '数据库中的数据';
                resolve(data);//成功时的用例,返回data作为value
                let err = '数据读取失败';
                reject(data);//失败时的用例,返回data作为reason
        },1000)
 });

 p.then(function(value){//常用value和reason
        console.log(value);
 },function(reason){
        console.error(reason);
 })

3.使用promise封装读取文件

实例:
 const fs = require('fs');//使用node.js的require方法来引入require模块
 const p = new Promise(function(resolve,reject){
        fs.readFile('./demo,md',(err,data)=>{
        if(err) 
            reject(err);//失败情况
        resolve(data);//成功情况
        });
 });

 p.then(function(value){
        console.log(value.toString());
 },function(reason){
        console.log('读取失败!');
 });

4.使用promise封装ajax

实例:
 const p = new Promise((resolve,reject)=\>{//创建一个promise对象
 const xhr = new XMLHttpRequest();//新建一个XMLHttpRequest对象
 xhr.open(‘GET’,’https://……’);//使用GET方法
 xhr.send();//发送请求
 xhr.onreadystatechange = function(){//当状态改变的时候触发onchange事件
        if(xhr.readyState === 4){//如果状态为4,代表请求已响应,到达了最后一个阶段
                if(xhr.status >= 200 && xhr.status < 300){//200~300之间为有效区间
                        resolve(xhr.response);//调用response方法
                }
                else{
                        reject(xhr.status);//调用reject方法
                } 
        }
    }
 });
 
 p.then(function(value){//使用then方法进行对promise对象的状态
        console.log(value);
 },function(reason){
        console.error(reason);//使用error在控制台进行警告
 })

5.promise中的then方法详解:(promise的prototype)

  1. then方法的返回结果是一个promise对象
  2. 如果返回是一个非promise属性的(return ’zsy’),则值为zsy
  3. 如果返回是一个promise属性的(return new promise()),则值为下一个的resolve或者reject值
  4. 如果抛出错误(throw new Error(’error!’)),则值为error,自动调用reject

6.使用promise方法异步读取多个文件的内容

实例:
 const fs = require('fs');//引入node.js中的fs模块
 const p = new Promise((resolve, reject) => {
        fs.readFile('./demo.md', (err, data) => {
                resolve(data);
        });
 });

 p.then(value => {
        return new Promise((resolve, reject) => {//返回新的promise对象
                fs.readFile('./demo2.md', (err, data) => {
                        resolve([value, data]);//合并返回结果
                })
        })
 }).then(value => {
        return new Promise((resolve, reject) => {//返回新的promise对象
                fs.readFile('./demo3.md', (err, data) => {
                        value.push(data);
                        resolve(value);
                })
        })
 }).then((value => {
        console.log(value.join('\r\n'));//打印查看
 }))

7.promise中的catch方法(其实就是一个语法糖)(只使用then也可以完成,只是catch可以提高代码的可读性)

用法:
 p.catch(function(reason){
        console.error(reason);
 })

十二、集合

1.集合Set类似于数组,不过元素都是唯一的(成员元素不允许重复),内置了iterator方法,可以使用「扩展运算符」

进行遍历,也内置了一些API,可以查看文档进行学习

2.Set可以用于数组去重

 let arr = [1,2,3,2,1,2,3];
 let result = […new Set(arr)];

3.Set可以用于求交集、并集、差集

 //交集
 let arr = [1,2,3,2,1,2,3];
 let arr2 = [1,2,1,1];
 let result = […new Set(arr)].filter(item=\>{//filter方法的作用:使用指定的函数测试所有元素,并创建一个包含所有通过测试的元素的新数组。
        let s2 = new Set(arr2);
        if(s2.has(item)){
                return true;
        }
        else{
                return false;
        }
 });

 //并集
 let union = […new Set([arr1,arr2])];

 //差集
 let diff = [..new Set(arr)].filter(item=>!new Set(arr2),has(item));

十三、Map

1.Map是键值对的集合,但是键不仅限于字符串,可以是各种类型的值,并且内置了iterator方法,可以使用for…of…进行遍历

简单的Map的使用方法
 let m = new Map();
 m.set('change',function(){
        console.log(‘I am zsy.’);
 });
 let key = {
        school:'XDU',
 };

 m.set(key,['南校区','北校区');
 console.log(m.size);
 console.log(m.get('change'));
 console.log(m.get(key));
 m.delete('change');

十四、class类

1.class可以声明类,作为对象的模板(其实也是一个语法糖)

简单的使用
 //使用ES5的方法通过构造函数进行对象的实例化
 function Phone(brand,price){
        this.brand = brand;
        this.price = price;
 }

 Phone.prototype.call = function()
        console.log('我可以打电话!');
 }

 let HuaWei = new Phone('华为',5999)
 HuaWei.call();
 console.log(HuaWei);

 //使用ES6的class来实现对象的实例化
 class Phone{
        //constructor名字不能修改
        constructor(brand,price){
                this.brand = brand;
                this.price = price
        }
        call(){
                //方法必须使用call方法,不可以使用call:function()的用法
                console.log('我可以打电话!');
        }
 }

 let onePlue = new Phone('一加',5999);
 console.log(onePlus);

2.class拥有static静态成员

用法
 class Phone{
        static name = '手机';
         static change(){
            console.log('I can change the world!');
        }
 }

 let nokia = new Phone();
 console.log(nokia.name);//Undefined
 console.log(Phone.name);//手机
 //说明了静态成员只属于这个类而不属于实例化对象

3.类继承

 //ES5中构造函数的继承
 function Phone(brand,price){
        this.brand = brand;
        this.price = price;
 }
 Phone.prototype.call = function(){
        console.log('我可以打电话');
 }
 function SmartPhone(brand,price,color,size){
        Phone.call(this.brand,price);
        this.color = color;
        this.size = size;
 }

 SmartPhone.prototype = new Phone;
 SmartPhone.prototype.constructor = SmartPhone;
 SmartPhone.prototype.photo = function(){
        console.log('我可以拍照');
 }
 SmartPhone.prototype.playGame = function(){
        console.log('我可以玩游戏');
 }
 
 const chuizi = new SmartPhone('锤子',3999);//实例化对象
 console.log(chuizi);
 
 //ES6中的类继承
 class Phone{
        constructor(brand,price){
                this.brand = brand;
                this.price = price;
        }
        call(){
                console.log('我可以打电话!');
        }
 }

 class SmartPhone extends Phone{//使用extends进行继承
        constructor(brand,price,color,size){
                super(brand,price);//使用super
        }
        photo(){
                console.log('拍照');
        }
        play(){
                console.log('玩游戏')
        }
 }
 const xiaomi = new SmartPhone('小米',799,'black','4.7inch');
 console.log(xiaomi);

4.子类对父类的重写

  //直接在子类中写重名的父类方法即可

5.ES6中的get和set

简单用例
  class Phone{
        get price(){//每次调用price成员都会自定调用get方法
                console.log(‘价格属性被读取!’);
                return '11';//返回值就是price成员的
        }
        set price(newVal){//注意get方法必须有一个参数,每次更改price成员的值都会调用set方法
        console.log('价格属性被修改!');
        }
  }

  let s = new Phone();//实例化对象
  console.log(s.price);//价格属性被读取!
                       //undefined

十五、ES6中的数值扩展

1.Number.EPSILON表示JavaScript中的最小精度(小数点后16位)

用例:
  function equal(a,b){
            if(Math.abs(a-b) < Number.EPSILON){
                    return true
            }else{
                    return false;
            }
  }

  console.log(0.1+0.1 === 0.3);//false
  console.log(equal(0.1+0.2,0.3));//true

2.二进制和八进制

用例:
  let a = 0b0101;//二进制
  let b = 0o777;//八进制
  let c = 100;//十进制
  let d = 0xff;//十六进制

3.Number.isFinite判断是不是一个有限数

4.Number.isNaN检测一个数是否为NaN

5.Number.parseInt~~~Number.parseFloat 字符串转整数

6.Number.isInteger检测一个数是否为整数

7.Math.trunc将数字的小数部分抹掉

8.Math.sign判断数字是正数负数还是零

十六、ES6的对象方法扩展

1.Object.is 判断两个值是否完全相等

简单用例
  console.log(Object.is(NaN,NaN));//使用对象的方法两个NaN是相等的
  console.log(NaN,NaN);//使用等号判断,两个NaN是不相等的

2.Object.assign对象的合并

    const config1 = {
            host:'localhost',
            port:3306,
            name:'zsy',
            pass:'zsy'
    }

    const config2 = {
            host:'localhost2',
            port:3306,
            name:'root',
            pass:'root'
    }

 console.log(Object.assign(config1,config2));//config1会被config2覆盖掉,如果有一种元素1中有但是2中没有那么会直接添加到2中

3.Object.setPrototypeof~~~Object.getPrototypeof进行设定原型对象和获取原型对象

十七、ES6模块化

1.有助于处理各个模块之间的冲突,易于维护,易于修改

2.ES6之前的模块化规范主要有:

1. CommonJS => NodeJS、Broeserify
2. AMD => requireJ
3. CMD => seaJS

3.模块化功能主要由两个命令构成:export和import

1)export命令用于规定模块的对外接口
2)import命令用于输入其他模块提供的功能

4.模块化的简单用例:

    //三种暴露的方法
    //index.html
    <script type='module'>
            import * as m1 from './src/js/m1.js';//使用import引入接口
            import * as m2 from './src/js/m2.js';
            import * as m3 from './src/js/m3.js'; 
            console.log(m1);
            console.log(m2);
    </script>
    
    //m1.js
    export let school = 'XDU';//使用export暴露数据,分别暴露
    export function teach(){
            console.log('我是zsy!');
    }
    
    //m2.js
    let school = 'zsy';
    function findJob(){
            console.log('hahaha');
    }
    export{school,findJob};//统一暴露
    
    //m3.js
    export default{//默认暴露
            let school = 'XDU';
    }

5.导入模块的方式

    //通用的导入方式
    import * as m1 from './src/js/m1.js';//使用import引入接口
    import * as m2 from './src/js/m2.js';
    import * as m3 from './src/js/m3.js'; 
    //解构赋值形式
    import {school,teach} from './src/js/m1.js';
    import {school as guigu,findJob} from './src/js/m2.js';//as后面的作为别名,可以不引起重名的冲突
    //应对默认暴露的方式,不经常使用
    import {default as m3} from './src/js/m3.js';//对default进行一个别名设置,不能直接使用default
    //只能针对默认暴露的简单写法,很常用
    import m3 from './src/js/m3.js'

6.浏览器使用模块化的两种方式

  1. 使用import引入
  2. 建立一个入口文件然后仅直接引入入口文件

十八、ES6使用babel对模块化代码进行转换

1.安装babel,具体内容可以详细学习

简单步骤:
  1. 安装工具:babel-cli babel-preset-env browserify(或webpack)
  2. 转换:npx babel src/js -d dist/js
  3. 打包:npx browserify dist/js/app.js(源路径) -o dist/bundle.js(目标路径)
  4. 每次更新都要重新转换和打包

十九、ES6模块化引入NPM包

1.下载并且安装包

2.import 变量名 from ‘路径’;