ES6入门笔记(进阶)


Promise

 1. 作用是解决异步回调的问题,传统回调问题是通过函数的回调函数完成的,这样就会一直嵌套回调函数

 // 例: 

let a = 10;

let promise = new Promise(function(resolve,  reject) {

        if(a=10) {

                resolve("成功");     // 启动promise之后,成功状态下返回resolve的内容

        }else{

                reject("失败");        // 启动promise之后,失败状态下返回reject的内容

         }

});

// promise.then(success, fail);        then会回调promise的状态一般then的第一个参数表示调用成功状态,第二个表示调用失败状态。

promise.then (res => {

         console.log(res);

         }, err => {

         console.log(err);

});

// PS:捕获错误的第二种方法promise.catch(err=>{...}),也可以连起来使用,因为then()返回的也是promise对象。promise.then(res=>{...}).catch(err=>{...})

2. promise.resolve()和promise.reject()    可以单独分开使用,相当于创建promise对象时只创建其中某一种状态。

         promise.resolve("aa"):将括号中的参数转成一个promise对象, resolve(成功)状态

               等价于

               new Promise(resolve => {

                      resolve(aaa")

               });

        promise.reject("aa"):将括号中的参数转成一个 promise对象, reject(失败)状态。

               等价于

               new Promise((resolve, reject)=>{

                      reject(aaa")

               });

3. Promise.all([对象1,对象2....])        批量处理promise对象,将对象打包成一个数组再处理,但必须保证所有的对象都是resolve(成功)状态。

// 例:

let p1 = new  Promise(function(resolve, reject) {

        resolve('aaa');

})

let p2 = new  Promise(function(resolve, reject) {

        resolve('bbb');

})

let p3 = new  Promise(function(resolve, reject){

        resolve('ccc');

})

Promise.all([p1, p2, p3]).then(res => {

        console.log(res);

})

4. Promise.race([对象1,对象2....])          批量处理promise对象,将对象打包成一个数组再处理,异步中只要有一个先解决了就返回解决的那个,不论是resolve还是reject

// 例:

let p1 = new  Promise(function(resolve, reject){

        setTimeout(() => {

                resolve('aaa')

        }, 1000);

})

let p2 = new  Promise(function(resolve, reject){

        setTimeout(() => {

                resolve('bbb')

        }, 100);

})

let p1 = new  Promise(function(resolve, reject){

        setTimeout(() => {

                reject('ccc')

        }, 500);

})

Promise.race([p1, p2, p3]).then(res => {

        console.log(res);       //返回结果ccc

})


模块化

1. ES6之前主要用的规范:

        commonjs    主要服务端 nodeJs          require('http')

        AMD      客户端  requireJs, curlJs

        CMD      客户端  sealJs

        ES6统一了服务端和客户端的模块化规范

2. 定义模块化   export 要定义的内容 或 export { }

 // 例1:

export  const a = 12;

// 例2:

const a = 5;

let b = 23;

export {a, b}

export {a as first, b as second}          //as 别名

3. 如何使用模块化  import 

        <script type=”module”>

                import  ....  或 import {..}  from ...   或import * as 别名 from ...

        </script>

// 例1:

<script type='module'>

        import  './user.js';          //引入路径

</script>

// 例2:

<script type='module'>

        import  {a, b, c}  from  './user.js';       //引入文件中的变量值

</script>

// 例3:

<script type='module'>

        import  * as all  from  './user.js';       //引入文件中所有的变量值

</script>

PS:  ①import引入的路径可以是相对路径,也可以是绝对路径

        ②import只会引入一次,且import “./user.js”这种用法只是单纯的引入文件。

        ③import引用会提升到最前面,所以写在代码哪里都行。

       ④import引入的js文件,如果发生修改,Import引用时也会相应修改,不会因为只引用就不会修改。

4. export和import的联系

        export定义的变量(值) ,如果是export default a=12 则在import时,不需要加”{}”,直接写import a from './user.js',如果是export { ... }或者不是default的状态,import时就必须要加”{}”,即import  {a,b,c}  from  './user.js'。

5. 动态引入 import(路径)

        import(路径)类似node里面require,可以动态引入。解决了引入只能静态先引后用,无法进行先判断后引用的问题。可以按需加载。返回值是个 promise对象。

// 例:

function config(count) {

        if (count === 1) {

                return  "./user.js";

        } else {

                return  "./info.js";

        }

}

import(config(2)).then(res => {

        console.log(...);        // 只有当count=2时才加载

});


类和继承

 1. 传统的类(面向对象):

        构造函数:

 function Person(name, age) {

        this.name = name;

        this.age = age;

}

        原型:

 Person.prototype.show = function() {

        return `个人信息:名字${this.name},---年龄${this.age}`;

}

        New一个对象:

var person1 = new Person("jack", "18");

console.log(person1.show());

2. ES6中的类(关键字 class constructor)

 class Person {

        constructor(name, age) {           //构造函数,new一个对象时自动执行

                this.name = name;

                this.age = age;

        }

        showName() {            //方法

                return `我的名字:${this.name}`;

        }

        showAge() {                 //方法

                return `我的年龄:${this.name}`;

        }

}

let person1 = new Person("jack", "18");

console.log(person1.showName());

// PS:也可以用一个变量代替类,如const Person = class {.....}

3. 注意点1: 类外变量引入

let showAge = "userinfo";

class Person {

        constructor(name) {          // 构造函数,new一个对象时自动执行

                this.name = name;

                this.age = age;

        }

        showName() {            // 方法

                return `我的名字:${this.name}`;

        }

        [showAge]() {

                return `我的年龄:${this.name}`;

        }

}

let person1 = new Person("jack", 18);

console.log(person1.showName());        // 我的名字:jack

console.log(person1.userinfo());    // 我的年龄:18

// PS:这里将类外面的变量showName传入方法名的方括号中,作为一个属性,其实[showName]就等于userinfo,所以在调用时可以用person1.userinfo()。

4. 注意点2: 变量提升

let person1 = new Person("jack");

console.log(person1.showName());          // 结果是undefined

class Person {

        constructor(name) {          // 构造函数,new一个对象时自动执行

                this.name = name;

        }

        showName() {            // 方法

                return `我的名字:${this.name}`;

        }

}

// PS:传统类存在变量提升的情况,可以先使用后声明,class类要先声明再调用,不存在变量上升的情况。

5. 注意点3: this的问题

有时候this会指向运行环境的window,因此想强行制定this为实例的对象,可以采用如下方法:

  • 在constructor中显示绑定:this.showName=this.showName.bind(this);
  • 使用箭头函数,因为箭头函数没有this,函数里的this只会继承最近的作用域。也就是Person实例。

class Person {

        constructor(name) {          // 构造函数,new一个对象时自动执行

                this.name = name;

        }

        showName() {            // 方法

                return `我的名字:${this.name}`;

        }

}

let person1 = new Person("jack");

let  show =  person1.showName;       

show( )        // 结果会报错,找不到name,因为this指向window

6. 注意点4: class也存在setter(设置值)和getter(取值)

class Person {

        constructor(name) {          //构造函数,new一个对象时自动执行

              this.name = name;

        }

        set  Name(val) {               

                return `我的名字:${val}`;

        }

        get  Name() {

                return `我的名字:${this.name}`;

        }

}

let person1 = new Person("jack");

person1.Name="jack";             // 触发set

console.log(person1.Name);             // 触发get

7. 注意点5: 静态方法(static)         // 调用时不是对象实例调用,而是类本身调用。

class Person {

        constructor(name) {          // 构造函数,new一个对象时自动执行

                this.name = name;

        }

        showName() {

                return `我的名字:${this.name}`;

        }

        static  info() {

                return "这是静态方法";

        }

}

let p1 = new Person("jack");

p1.showName();      // 正常状态调用方法

Person.info();  // 调用静态方法

8. 类的继承

        原生js的继承方式:用call和apply继承属性,用prototype继承方法。

// 例:

// 父类

function Person(name) {

        this.name = name;

}

Person.prototype.showName = function() {

        return this.name;

}

// 子类

function Student(name,age) {

        Person.call(this, name);             // 继承属性

        this.age = age;

}

Student.prototype = new Person();                   // 继承方法

let st = new Student("jack", 18);

console.log(st.showName());

        ES6中的继承:关键字(extends,super)

// 例:

// 父类

class Person {

        constructor(name) {          // 构造函数,new一个对象时自动执行

                this.name = name;

        }

        showName() {

                return `我的名字:${this.name}`;

        }

}

// 子类

class Student extends Person {

        constructor(name,age){           // 这里的name是继承自父类的,age是子类单独的。

                super(name);           // 继承父类的内容

                this.age = age;          // 自己的内容

        }

        showName() {           

                //子类的方法如果和父类重名就会覆盖父类的方法,但是用super.就会防止方法覆盖

                 super.showName();         // 继承自父类的方法

                console.log("这是子类的方法");    // 子类自己的方法

        }

        showAge() {                 // 子类的方法

                return `我的年龄:${this.name}`;

        }

}

let st = new Student("jack",18);

console.log(st.showName());


Symbol & Generator

1. Symbol是一个数据类型,类似于Number,Boolean

        定义:let syb = Symbol("aaa");

        // PS: Symbol数据类型不能像其它数据类型一样new

2. Symbol()返回一个唯一的值。

        一般用于key使用,定义一些唯一的或者私有的东西。

3. symbol是基本数据类型。

        和string,object,function,undefined,number,boolean一样

4. symbol作为key使用时,for..in..循环无法打印出结果。

5. generator函数解决异步,深入嵌套的问题。

// 定义:

function * gen() {              // 需要加上*

        yield 'welcome';

        yield 'to';

        return '牧码人';

}

手动单步调用:

let g1= gen();        // 创建generator对象

g1.next();        // {value:”welcome”, done:false}

g1.next();        // {value:”to”, done:false}

g1.next();        // {value:”牧码人”, done:true}

循环多步调用:for...of..., for..of..循环只能遍历出yield的内容,无法调用return的内容。

for(let val of g1) {     

        console.log(val);        // welcome  to           无法打印出牧码人

}

6. generator可以配合解构运算符,Array.from()来使用

7. generator配合axios使用

// 例:

function * gen() {

         let val = yield "jack"

         yield axios.get(`https://api.github.com/users/${val}`);

}

let g1= gen();

let username= g1.next().value;

g1.next(username).value.then(res => {

         console.log(res.data);

});


Async & await

1. Async的写法

        async function fn( ) {        // 表示异步,这个函数里面有异步任务

                (let result = ) await xxx     // 表示后面结果需要等待

        }

2. Async特点:

        (1). await只能放到 async函数中,配合使用。

        (2).相比 genrator语义化更强。

        (3). await后面可以是 promise对象,也可以数字、字符串、布尔值。

        (4). async函数返回是一个 promise对象

        (5).只要 await语句后面 Promise状态变成 reject,那么整个 async函数会中断执行。

3. 如何解决 async函数中抛出错误,影响后续代码执行的问题

        try{}catch(e){}

try {

        await Promise.reject("出错了");

} catch(e) {

        throw new Error()

}

await Promise.resolve("成功");

        Promise本身的catch

await Promise.reject("出错了").catch(err => {

        console.log(err);

});

4. 简单例子:

async function fn() {

        try{

                await Promise.resolve("seccess");

                await Promise.reject("error");

        }catch (e) {

                console.log(err);

        }

}

fn().then(res => {

        console.log(res);

}, err => {

        console.log(err);

});


Set和weakSet

1. 定义

        set是一种数据结构,类似数组,但是里面不能有重复值。格式:let setArr = new set(["a","b"]);      set中放的是一个数组

// 例:

let setArr = new Set('a','b','c','d');       //打印时显示{'a','b','c','d'}。

let setArr = new Set('a','b','c','b');       //打印时显示{'a','b','c'}, 因为b重复就会去掉。

2. Set的数据操作

        添加: add           // 返回set对象

// 例:

let setArr = new Set(["a"]);

setArr.add("b").add("c").add("d");

console.log(setArr);          // {'a','b','c','d'}

        删除: delete

// 例:

let setArr = new Set('a','b','c','d');

setArr.delete("a");

console.log(setArr);          // {'b','c','d'}

        查找: has

// 例:

let setArr = new Set('a','b','c','d');

setArr.has("a")          // true

setArr.has("e")          // false

        清空:clear

// 例:

let setArr = new Set(['a','b','c','d']);

setArr.clear();

console.log(setArr);          // {}

        查询Set数据类型的长度:size      =>区别于上边的方法,这个是属性.

// 例:

let setArr = new Set(['a','b','c','d']);

console.log(setArr.size);            // 4

let setArr = new Set('a','b','c','d');

console.log(setArr.size);            // 1

3. Set的循环操作

        Set循环时只能用到for(let item of ...), for in和其他的循环模式都不适用。

// 例:

var setArr = new Set(['a','b','c','d']);

for(let item of setArr) {

         console.log(item);

}

        用forEach()循环

// 例:

var setArr = new Set(['a','b','c','d']);

setArr.forEach((key,value) => {

        console.log(key, value);

})

4. Set也支持keys()、values()、entries()方法

// 例:

let setarr = new Set(['a','b','c','d']);

for(let item of setarr.keys()) {             // 键

        console.log(item);

}

for(let item of setarr.values()) {         // 值

         console.log(item);

}

for(let item of setarr.entries()) {        // 某一项

         console.log(item);

}

5. 利用set实现数组去重

// 例:

let arr=[1, 2, 3, 4, 5, 6, 7, 3, 4, 7, 2, 1];

let newArr=[...new Set(arr)];

console.log(newArr);        // [1, 2, 3, 4, 5, 6, 7]

6. Set和WeakSet的区别(一般不推荐用WeakSet)

        Set和WeakSet在用法上没有区别,但是WeakSet 的成员只能是对象,而不能是其他类型的值。WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。


Map和WeakMap

1. 定义

        Map是一种数据结构,类似json,但是json的键(key)只能是字符串,map的key可以是任意类型。

        例:

        let map = new Map();

2. Map的数据操作:

        设置值(set)和读取值(get)    map.set(key,value);   map.get(key);

// 例:

let map = new Map();

let json = {

       a: 1,

        b: 2

}

map.set('a', 'aaa');

map.set('a', json);

map.set(json, 'aaa');

map.get(json);        // 'aaa'

        删除: delete()

// 例:

let map = new Map();

map.set('a', 'aaa');

map.set('b','bbb');

map.delete('b');

        清空: clear()

// 例:

let map = new Map();

map.set('a', 'aaa');

map.set('b','bbb');

map.clear();     //{ 0 }

        查找: has()

例:

let map = new Map();

map.set('a', 'aaa');

map.set('b','bbb');

map.has('a');           // true

3. Map的循环操作

        Map和Set的循环一样,可参照Set的循环。

4. WeakMap和Map的区别

        Weakmap的key只能是对象,而Map的key可以是任意类型值


数字变化和Math新增的内容

1.Math.pow(底数,指数)       // 平

        Math.pow(底数,指数) = 底数**指数

// 例:

Math.pow(2, 3) = 2**3 = 8

2. 进制的写法:

  • 二进制(Binary): let a= 0b010101;
  • 八进制(Octal): let a= 0o666;
  • 十六进制: #ccc

3. Number.isFinite()  -->判断是不是数字

// 例:

let a = 10;

let b = '你好'

Number.isFinite(a)   // true

Number.isFinite(b)   // false

4. Number.isInteger()  --->判断数字是不是整数

// 例:

let a = 10;

let b = 10.5;

Number.isFinite(a)   // true

Number.isFinite(b)   // false

5. 之前学的Number()、 parseInt()、 parseFloat()也可以用于判断数字和数字转换。这里就不再细说了。

6. 安全整数

        范围: -(2^53 - 1) <= a <= (2^53 - 1)

        检验:Number.isSafeInteger(a);

        Number.MAX_SAFE_INTEGER  最大安全整数 ==(2^53 - 1)

        Number.MIN_SAFE_INTEGER  最小安全整数= -(2^53 - 1)

7. 其他零散知识:

  • Math.trunc()截取,只保留整数部分

        Math.trunc(4.5) -> 4

        Math.trunc(4.9) -> 4

  • Math.sign(5)    判断一个数到底是正数、负数、0

        Math.sign (-5) -> -1

        Math.sign(5) -> 1

        Math.sign(0) -> 0

        Math.sign(-0) -> -0

        其他值返回NaN

  • 开方

        二次方: Math.sqrt(要开方数)

        三次方: Math.cbrt(要开方数)


ES9中新增的内容

1. 命名捕获: ?<命名>

// 例:

let str = '2018-03-20'

let reg =/(?<year>\d{4})-(?<month>\d{2}-(?<day>\d{2})/;

let {year, month, day} =str.match(reg).groups;      // 存放在groups中

console.log(year, month, day);

2. 反向引用 (传统的和新增的可同时用)

        传统:\1  \2        replace中用 $1  $2

// 例:

let reg = /^(?<Strive>welcome)--\1$/

let str4='welcome--welcome';

console.log(reg.test(str4));        // true

// 例:

let str = '2018-03-20'

let reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;

str=str.replace(reg,'$1/$2/$3 ');

console.log(str);       // 2018/03/20

        新增:反向引用命名捕获--> 语法:\k<名字>        replace中用$<命名>

// 例:

let reg = /^(?<Strive>welcome)-\k<Strive>$/

let str = 'a-a';

let str2 = 'Strive-Strive';

let str3 = 'welcome-welcome';

console.log(reg.test(str));        // false

console.log (reg.test(str2));        // false

console.log(reg.test(str3));         // true

// 例:

let str='2018-03-20'

let reg =/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;

str=str.replace(reg,'$<year>/$<month>/$<day> ');

console.log(str);       // 2018/03/20

3. dotAll模式 ( s )

       之前’.’在正则里表示匹配任意东西,但是不包括\n、表情符号等,加上s,’.’就能真正匹配所有。

let reg=/^w+/gims

4. 标签函数 ( `` )

例:

function fn(arg) {

        console.log(arg);        // ["welcome"]

        }

fn`welcome`;


Proxy的使用

1. 理解Proxy

Proxy用于修改某些操作的默认行为,用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。等同与在语言层面做出修改,即对编程语言进行编程。Proxy 可以理解成,在目标对象之前架设一层”拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来”代理”某些操作,可以译为”代理器”。

2. 语法:

let p = new Proxy(target, handler);

        target:用Proxy包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。

        handler是一个对象,其属性是当执行一个操作时定义代理的行为的函数。

{

       set(target,property,value){},    //触发设置对象的时候要干的事情

         get(target,property){},     //触发获取对象信息的时候要干的事情

         deleteProperty(target,property){},         //触发删除对象信息的时候要干的事情

         has(target,property){},     //触发查询对象信息的时候要干的事情  'xxx' in obj

         apply(target,context,args)∥   调用函数处理,拦截函数        context是this指向。

         ....

}

3. apply需要和Reflect配合使用

        如果在proxy中单独使用apply,则在使用时只会拦截函数,不会执行其他内容,因此要想执行代理的函数就需要reflect.apply()反射配合使用。

        语法:Reflect.apply(调用的函数,this指向,参数数组),类似于call和apply。

// 例:

function sum(a,b) {

         return a+b;

}

let newSum = new Proxy(sum, {

         apply(target,cot,args) {

                   console.log("sum函数被拦截了");

                   return Reflect.apply(...arguments);

         }

});

console.log(newSum(2,3));        // 5


Reflect的使用

 1. reflect介绍

        Reflect 可以用于获取目标对象的行为,它与 Object 类似,但是更易读,为操作对象提供了一种更优雅的方式。它的方法与 Proxy 是对应的。ES6 中将 Object 的一些明显属于语言内部的方法移植到了 Reflect 对象上(当前某些方法会同时存在于 Object 和 Reflect 对象上),未来的新方法会只部署在 Reflect 对象上。Reflect 对象对某些方法的返回结果进行了修改,使其更合理。Reflect 对象使用函数的方式实现了 Object 的命令式操作。

2. Reflect的13种方法

  • Reflect.apply(target, thisArg, args)    //等同于Function.prototype. apply. call(func, thisArgs, args),用于绑定this对象后执行给定函数。
  • Reflect.construct(target, args)     //等同于new target(...args),这提供了一种不使用new,来调用构造函数的方法。
  • Reflect.get(target, name, receiver) //查找并返回target的name属性,如果没有,则返回undefined。如果name属性部署了读取函数(getter),则读取函数的this绑定的receiver。如果第一个参数不是对象,则Reflect.get则会报错。
  • Reflect.set(target, name, value, receiver)  //设置target对象的name属性等于value。如果name属性设置的赋值函数,则赋值函数的this绑定receiver。如果Proxy与Reflect联合使用,前者完成拦截赋值操作,后者完成赋值默认行为,而且传入了receiver,则Reflect.set会触发Proxy.defineProperty拦截。
  • Reflect.defineProperty(target, name, desc)      //等同于Object.define Property ,用来为对象定义属性。未来后者会被逐渐废除。如果第一个参数不是对象,就会抛出错误信息。
  • Reflect.deleteProperty(target, name)    //等同于delete obj[name],用于删除对象属性。
  • Reflect.has(target, name)   //对应 name in obj 里面的in操作,如果第一个参数不是对象,Reflect.has和in都会报错。
  • Reflect.ownKeys(target) //用于返回对象的所有属性,等同于Object.getOwnPropertyNames与Object.getOwnPropertySymbols之和。
  • Reflect.isExtensible(target)    //等同于Object.isExtensible,返回一个布尔值,表示当前对象是否可扩展。
  • Reflect.preventExtensions(target)   //等同于Object.preventExtensions,用于让一个对象变为不可扩展,返回一个布尔值,表示是否操作成功。
  • Reflect.getOwnPropertyDescriptor(target, name)  //等同于Object.getOwn PropertyDescriptor,用于得到指定属性的描述对象,将来会代替后者。
  • Reflect.getPrototypeOf(target)  //用读取对象的__proto__属性,对应Object.getPrototypeOf(obj)方法。
  • Reflect.setPrototypeOf(target, prototype)  //设置对象的__proto__属性,返回第一个参数对象,对应Object.setPrototypeOf(obj, newProto,如果第一个参数不是对象,Object.setPrototypeOf会返回第一个参数对象,而Reflect.setPrototypeOf会报错。如果第一个参数是undefined或null,则两个都会报错。

扩展知识:

        异步:不连续,上一个操作没有执行完,下一个操作照样开始

        同步:连续执行,上一个操作没有执行完,下一个没法开始

        关于异步,解决方案:

                a).回调函数

                b).事件监听

                c).发布/订阅

                d).Promise对象

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值