• javascript的ES6学习总结(第三部分)


    1.ES6中的面向对象的类

    1.1、定义类

    在ES5中,我们写一个类,通常是这么写的

    function Person(name,age){
        this.name = name;
        this.age = age;
    }
    /**
     * es5中的模拟面向对象的类的方法 写法1
    Person.prototype.showName = function(){
        return "名字为:"+this.name;
    }
    Person.prototype.showAge = function(){
        return "年龄为:"+this.age;
    }*/
    
    /**
     * es5中的模拟面向对象的类的方法 写法2
     *
     */
    Object.assign(Person.prototype,{
        showName(){
            return "名字为:"+this.name;
        },
        showAge(){
            return "年龄为:"+this.age;
        }
    });
    var p1 = new Person('tom',18);
    console.log(p1.showName());//名字为:tom
    console.log(p1.showAge());//年龄为:18

    在ES6中,我们可以这样写

    //ES6中的类(类名大小写都可以,推荐使用规范按照首字母大写)
    class Person{
        constructor(name,age){//构造方法(函数),每new一个新对象,自动执行
            // console.log(`构造函数执行了,${name},${age}`);//构造函数执行了,Lucy,18
            this.name = name;
            this.age = age;
        }
        showName(){
            return `名字为:${this.name}`;
        }
        showAge(){
            return `年龄为:${this.age}`;
        }
    }
    let p1 = new Person('Lucy',18);
    console.log(p1.showName(),p1.showAge());//名字为:Lucy 年龄为:18
    //ES6中的类(赋给一个变量或常量,类名大小写都可以,推荐使用规范首字母大写)
    const Person =  class{
        constructor(name,age){//构造方法(函数),每new一个新对象,自动执行
            // console.log(`构造函数执行了,${name},${age}`);//构造函数执行了,Lucy,18
            this.name = name;
            this.age = age;
        }
        showName(){
            return `名字为:${this.name}`;
        }
        showAge(){
            return `年龄为:${this.age}`;
        }
    }
    let p1 = new Person('Lucy',18);
    console.log(p1.showName(),p1.showAge());//名字为:Lucy 年龄为:18

    注意:

    1).ES6里面Class没有提升(例如ES5中的函数有提升到顶部的作用)

    2).ES6中的this,首先来看一下ES5中矫正this的几个方法

    (2.1) fn.call(this指向谁,args1,args2...);

    (2.2) fn.apply(this指向谁,[args1,args2...]);

    (2.3) fn.bind();(React中经常会用到)

    其中,(2.1) fn.call和(2.2) fn.apply都会在矫正this的时候,方法(函数)会调用一次

    class Person{
        constructor(){
            this.name = 'jason';
            this.showName = this.showName.bind(this);//矫正this
        }
        showName(){
            console.log('this:',this);//this: Person {name: "jason", showName: function}
            return `名字为:${this.name}`;
        }
    }
    let p1 = new Person();
    let {showName} = p1;
    console.log(showName());//名字为:jason

    1.2、类里面的取值函数(getter)和存值函数(setter):

    class Person{
        constructor(name){
            this.name = name;
        }
        get aaa(){
            return `获取aaa的名字,值为${this.name}`;
        }
        set aaa(val){
            console.log(`设置aaa的名字,值为${val}`);
        }
    }
    let p1 = new Person('jack');
    console.log(p1.aaa);//获取aaa的名字,值为jack
    p1.aaa = 'luke';//设置aaa的名字,值为luke

    1.3、类里面的静态方法(就是类身上的方法)

    class Person{
        constructor(){
    
        }
        showName(){
            return '这是showName方法';
        }
        static aaa(){
            return '这是静态方法';
        }
    }
    let p1 = new Person();
    console.log(p1.showName());//这是showName方法
    console.log(Person.aaa());//这是静态方法

    1.4、类里面的继承

    先来回顾一下ES6之前的继承写法

    1.原型链继承

    //父类
    Animal.prototype.eat = function(food) {
        console.log(this.name + '正在吃' + food);            
    }
    function Animal(name) {
        this.color = ['green','red','blue'];
        this.name = name || 'animal';
        this.sleep = function() {
            console.log(this.name + "正在睡觉")
        }
    }

    原型链继承核心: 将父类的实例作为子类的原型。

    //子类
    function Cat(name) {
        this.name = name
        this.color = ['green','red','blue'];//引用类型值,,所有实例会共享这个属性。
    }
    Cat.prototype = new Animal();
    var cat = new Cat('cat');
    console.log(cat.name);
    console.log(cat.eat('fish'));
    console.log(cat instanceof Animal);
    console.log(cat.sleep());

    缺点:

    但是,原型链式继承并没有实现代码的复用,一些共同的属性:如name,在子类中还是得重新写一遍(即同一套代码还是得重新写)。

    再者,cat继承了Animal实例的所有属性和方法,这些方法并不都是我们需要的,也就是过多的继承了没有用的属性。且如果原型中包含引用类型值,那么所有的实例会共享这个属性。

    2.构造函数继承

    function Person(name,age,sex){
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    function Student(name,age,sex){
        Person.call(this,name,age,sex);
        this.grade = grade;
    }
    let student = new Student;

    优点:

    • 构造函数模式继承实现了代码的复用

    缺点:

    • 不能继承借用的构造函数的原型,只能借用构造函数本身的属性和方法
    • 每次构造函数都要多走一个函数

    3.组合继承

    // 父类
    function Person(name){
        this.name = name;
    }
    Person.prototype.showName = function(){
        return `名字是:${this.name}`
    };
    // 子类
    function Student(name,age){
        Person.call(this,name);//继承属性,在创建实例时第二次调用Person
        this.age = age;
    }
    Student.prototype = new Person();//继承方法,第一次调用Person
    Student.prototype.constructor = Student;//矫正constructor
    Student.prototype.sayName = function(){
        return '年龄是:'+this.age;
    }
    // 调用
    var stu1 = new Student('jack',20);
    console.log(stu1.name);//jack
    console.log(stu1.showName);//function (){return `名字是:${this.name}`}
    console.log(stu1.showName());//名字是:jack
    console.log(stu1.sayName());//年龄是:20

    缺点:

    • 父类构造函数被调用2次,子类实例的属性存在两份,一份在原型上,一份在实例属性上。造成内存的浪费。

    4.寄生组合式继承

    寄生组合式继承是对组合继承的进一步优化。我们先看一下为什么要写这个语句。

    SubType.prototype = new SuperType();

    我们无非是想让SubType继承SuperType的原型。但是我们为什么不直接写成这样呢?

    SubType.prototype = SuperType.prototype

    这样写确实可以实现子类对象对父类对象原型的继承。但是这样写的话:所有继承该父类的子类对象的原型都指向同一个了。也就是说SubType不能有自己的原型了。这显然不是我们想要的。

    既然不能直接继承,那可不可以间接继承SuperType.prototype呢。这就是最终的解决方案:寄生组合式继承

    我们让一个函数去指向SuperType.prototype,然后让SubType.prototype指向这个函数产生的对象不就可以了嘛。

    function inherit(Target,Origin) {//实现寄生组合式继承的核心函数
        function F() {};
        F.prototype = Origin.prototype; //F()的原型指向的是Origin
        Target.prototype = new F(); //Target的原型指向的是F()
        Target.prototype.constructor = Target; 
        SubType.prototype.__proto__ == SuperType.prototype
    }
    
    function SuperType(name) {
        this.name = name;
        this.colors = ['red','blue','pink'];
    }
    SuperType.prototype.sayName = function() {
        console.log(this.name);
    }
    function SubType(name,age) {
        //继承属性
        SuperType.call(this,name);//在创建实例时第二次调用SuperType
        this.age = age;
    }
    
    inherit(SubType,SuperType);//实现寄生组合式继承

    我们再来看一下实现寄生组合式继承的核心函数。F函数其实是通用的,我们没必要每次进入inherit函数时都声明一遍。所以我们可以用闭包的形式来写:

    var inherit = (function () {
            var F = function () {};
            return function (Target , Origin) {
                F.prototype = Origin.prototype;//F()的原型指向的是Origin
                Target.prototype = new F();//Target的原型指向的是F()
                Target.prototype.constructor = Target;
                Target.prototype.uber = Origin.prototype;
                SubType.prototype.__proto__ == SuperType.prototype
            }
        })()

    再来看看ES6继承的写法,相比前面就优雅了许多,代码量也会少很多!!!

    /* ES6继承 */
    // 父类
    class Person{
        constructor(name){
            this.name = name;
        }
        showName(){
            return `名字为:${this.name}`;
        }
    }
    // 子类
    class Student extends Person{
    
    }
    // 调用
    var stu1 = new Student('jack');
    console.log(stu1.showName());//名字为:jack

    子类在自己的身上加方法:

    /* ES6继承 */
    // 父类
    class Person{
        constructor(name){
            this.name = name;
        }
        showName(){
            return `名字为:${this.name}`;
        }
    }
    // 子类
    class Student extends Person{
        constructor(name,skill){
            super(name);//子类的构造函数必须有super(),相当于执行一次父级的构造函数
            this.skill = skill;
        }
        showSkill(){
            return `他的名字是${this.name},他的特长是${this.skill}`;
        }
    }
    // 调用
    var stu1 = new Student('jack','跳舞');
    console.log(stu1.showSkill());//他的名字是jack,他的特长是跳舞

    如果子类的方法和父类的方法同名,然后想调用父类的方法,自己子类的方法也要执行,可以这么写

    /* ES6继承 */
    // 父类
    class Person{
        constructor(name){
            this.name = name;
        }
        showName(){
            console.log('父类的showName');
            return `名字为:${this.name}`;
        }
    }
    // 子类
    class Student extends Person{
        constructor(name,skill){
            super(name);//子类的构造函数必须有super(),相当于执行一次父级的构造函数
            this.skill = skill;
        }
        showName(){
            super.showName();//执行父类的方法
            /* 这里写子类自己的要做的事 */
            console.log('子类的showName');
        }
        showSkill(){
            return `他的名字是${this.name},他的特长是${this.skill}`;
        }
    }
    // 调用
    var stu1 = new Student('jack','跳舞');
    console.log(stu1.showName());//父类的showName  子类的showName

    2.Symbol和Generator

    2.1Symbol:ES6新增的一种数据类型

    定义方法:let Symbol = Symbol('aaa');

    注意:

    (1)Symbol不能当new来使用

    (2)Symbol()返回是一个唯一值

    (3)Symbol是一个单独数据类型,就叫symbol的基本类型

    (4)如果Symbol作为key,用for in循环,出不来

    let symbol = Symbol('Jack');
    let json = {
        a:'apple',
        b:'banana',
        [symbol]:'aaa'
    }
    console.log(json[symbol]);//aaa
    // 遍历json
    for(let key in json){
        console.log(key);//a b
    }

    2.2Generator生成器函数:解决异步,深度嵌套的问题

    语法:

    function * show(){
    
    }
    function* show(){
    
    }
    function *show(){
    
    }

    定义&调用:

    function * gen(){//在函数名前面使用*号定义一个
        yield 'hello';
        yield 'javascript';
        return 'generator函数';
    }
    let g1 = gen();
    console.log(g1.next());//Object {value: "hello", done: false}
    console.log(g1.next());//Object {value: "javascript", done: false}
    console.log(g1.next());//Object {value: "generator函数", done: true}
    console.log(g1.next());//Object {value: undefined, done: true}

    遍历generator函数:

    function * gen(){//在函数名前面使用*号定义一个
        yield 'hello';
        yield 'javascript';
        yield 'world';
        return 'generator函数';
    }
    let g1 = gen();
    /*遍历generator函数(注意:return的东西不会被遍历出来)*/
    // 1.用for...of遍历
    for(let val of g1){
        console.log(val);//hello javascript world
    }
    // 2.使用解构
    let [a,b,c,d] = gen();
    console.log(a,b,c,d);//hello javascript world undefined
    // 3.使用扩展(三个点)运算符
    let [f,...g] = gen();
    console.log(f,g);//hello ["javascript", "world"]
    
    let [...newArr] = gen();
    console.log(newArr);//["hello", "javascript", "world"]
    //4.使用Array.from函数
    console.log(Array.from(gen()));//["hello", "javascript", "world"]

    关于异步的解决方案:

    (1)回调函数

    (2)事件监听

    (3)发布/订阅

    (4)Promise对象

    (5)Generator函数

    (6)Async/Await

    3.async、await函数:解决异步问题

    定义:在函数前面加async,函数内部加await,后面的代码会等待前面的代码先执行

    语法:

    async function fn(){//表示异步,这个函数里面有异步的任务
        let result=await;//表示后面结果需要等待   
    }

    使用(例如读取文件):

    (1)promise写法:

    const fs = require('fs');
    
    // 用fs封装一个promise
    const readFile = function(fileName){
        return new Promise((resolve,reject)=>{
            fs.readFile(fileName,(err,data)=>{
                if(err) reject(err);
                resolve(data);
            })
        })
    }
    
    // promise
    readFile('data/1.txt').then(res=>{
        console.log(res.toString());
        return readFile('data/2.txt');
    }).then(res=>{
        console.log(res.toString());
    });

    (2)generator写法:

    const fs = require('fs');
    
    // 用fs封装一个promise
    const readFile = function(fileName){
        return new Promise((resolve,reject)=>{
            fs.readFile(fileName,(err,data)=>{
                if(err) reject(err);
                resolve(data);
            })
        })
    }
    
    // generator
    function * gen(){
        yield readFile('data/1.txt');
        yield readFile('data/2.txt');
    }
    let g1 = gen();
    g1.next().value.then(res=>{
        console.log(res.toString());
        return g1.next().value;
    }).then(res=>{
        console.log(res.toString());
        return g1.next().value;
    });

    (3)async、await写法:

    // 用async、await做一个文件读取
    const fs = require('fs');
    
    // 用fs封装一个promise
    const readFile = function(fileName){
        return new Promise((resolve,reject)=>{
            fs.readFile(fileName,(err,data)=>{
                if(err) reject(err);
                resolve(data);
            })
        })
    }
    
    // async
    async function fn(){//表示异步,函数内有异步任务
        let f1 = await readFile('data/1.txt');//表示后面的结果需要等待
        console.log(f1.toString());
        let f2 = await readFile('data/2.txt');
        console.log(f2.toString());
    }
    fn();

    async、await特点:

    1.await只能放在async函数中

    2.相比generator语法更强

    3.await后面可以是promise对象,也可以是数字、字符串、布尔类型

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

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

    如何解决async函数中抛出错误,影响后续代码执行?

    1.使用try{}catch(e){}语法

    async function fn(){
        try{
            await Promise.reject('出现问题了');
        }catch(e){
    
        }
        let a = await Promise.resolve('successs');
        console.log(a);
    }
    fn().then(res=>{
        console.log(res);
    }).catch(err=>{
        console.log(err);
    });
    // 结果
    // success undefined

    2.promise本身的catch

    async function fn(){
        let [a,b] = await Promise.all([
            readFile('data/1.txt'),
            readFile('data/2.txt')
        ]);
        console.log(a.toString());
        console.log(b.toString());
    }
    fn();

    4.Set和WeakSet

    4.1、Set数据结构:类似数组,但里面不能有重复值。new Set([]),存储数组

    用法:

    // Set数据结构
    let setArr = new Set(['a','b','a']);
    console.log(setArr);//Set(2) {"a", "b"}

    方法:

    (1)add()方法:向Set数据结构中添加元素

    // Set数据结构--add()方法:向数组中添加元素
    let setArr = new Set();
    setArr.add('aaa');
    setArr.add('bbb');
    setArr.add('aaa');
    console.log(setArr);//Set(2) {"aaa", "bbb"}
    // add()方法链式添加
    let setArr = new Set().add('aaa').add('bbb').add('aaa');
    console.log(setArr);//Set(2) {"aaa", "bbb", "ccc"}

    (2)delete()方法:删除Set数据结构中的某一项

    let setArr = new Set();
    setArr.add('aaa');
    setArr.add('bbb');
    setArr.add('ccc');
    console.log(setArr);//Set(2) {"aaa", "bbb","ccc"}
    // Set数据结构--delete()方法:删除Set数据结构中的某一项
    setArr.delete('bbb');
    console.log(setArr);//Set(2) {"aaa", "ccc"}

    (3)clear()方法:删除Set数据结构中的所有项

    // Set数据结构--add()方法:向Set数据结构中添加元素
    let setArr = new Set();
    setArr.add('aaa');
    setArr.add('bbb');
    setArr.add('ccc');
    // Set数据结构--clear()方法:删除Set数据结构中的所有项
    setArr.clear();
    console.log(setArr);//Set(0) {}

    (4)has()方法:检测Set数据结构中的是否某一项,返回布尔值

    let setArr = new Set();
    setArr.add('aaa');
    setArr.add('bbb');
    setArr.add('ccc');
    // Set数据结构--has()方法:检测Set数据结构中的是否某一项,返回布尔值
    console.log(setArr.has('bbba'));//false

    (5)size属性:查看Set数据结构有多少个元素

    let setArr = new Set();
    setArr.add('aaa');
    setArr.add('bbb');
    setArr.add('ccc');
    // Set数据结构--size属性:查看Set数据结构有多少个元素
    console.log(setArr.size);//3

    (6)循环Set数据结构(注:Set数据结构的key和value是相同的)

    for(let val of setArr){//默认循环的是values()
        console.log(val);//aaa bbb ccc
    }
    console.log('-------');
    for(let val of setArr.keys()){
        console.log(val);//aaa bbb ccc
    }
    console.log('-------');
    for(let val of setArr.values()){
        console.log(val);//aaa bbb ccc
    }
    for(let item of setArr.entries()){
        console.log(item);//["aaa", "aaa"] ["bbb", "bbb"] ["ccc", "ccc"]
    }
    for(let [k,v] of setArr.entries()){
        console.log(k,v);//aaa aaa bbb bbb ccc ccc
    }
    setArr.forEach((val,index)=>{
        console.log(val,index);//aaa aaa bbb bbb ccc ccc
    });

    利用Set做数组的去重:

    方法1

    let arr = [1,2,3,4,5,6,3,4,5,3,2];
    let newArr = [...new Set(arr)];//这里数组去重返回的是一个数组的浅拷贝
    arr.push(9,8,7,7,8);
    console.log(arr);//[1, 2, 3, 4, 5, 6, 3, 4, 5, 3, 2, 9, 8, 7, 7, 8]
    console.log(newArr);//[1, 2, 3, 4, 5, 6]

    方法2

    let arr2 = [1,2,3,4,5,6,3,4,5,3,2];
    let newArr2 = new Set();
    arr2.map(x=>newArr2.add(x));
    let resArr2 = [...newArr2];
    console.log(resArr2);[1, 2, 3, 4, 5, 6]

    4.2、WeakSet数据结构:类似数组对象,但里面不能有重复值。new WeakSet({}),存储对象

    注意:

    1.WeakSet初始化定义时,不能在里面存值。

    2.WeakSet里面的add()方法只能存json对象,如果存字符串、数字等会报错!

    定义:

    let set = new WeakSet();//WeakSet初始化定义时,不能在里面存值。
    let json = {
        a:1,
        b:2
    };
    let json2 = {
        a:'asp',
        b:2
    };
    set.add(json);
    set.add(json2);//add()方法只能存json对象,如果存字符串、数字等会报错!
    //set.add(true);//Invalid value used in weak set
    console.log(set);//WeakSet {Object {a: "asp", b: 2}, Object {a: 1, b: 2}}

    方法:Set数据结构提供的方法除了size属性和clear()方法没有,别的都有。(例如:add()、has()、delete())

    5.Map和WeakMap

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

    使用:

    // Map使用
    let map = new Map();
    map.set(key,value);

    方法:

    // Map使用
    let map = new Map();
    let json = {
        a:1,
        b:2
    }
    
    // map.set(key,value);//设置一个值
    
    map.set('abc','123');
    map.set(json,'aaa');
    map.set('a',json);
    console.log(map);//Map(3) {"abc" => "123", Object {a: 1, b: 2} => "aaa", "a" => Object {a: 1, b: 2}}
    
    // map.get(key);//获取一个值
    
    console.log(map.get(json));//aaa
    console.log(map.get('a'));//Object {a: 1, b: 2}
    
    // map.delete(key);//删除某一项
    
    map.delete('abc');
    console.log(map);//Map(2) { Object {a: 1, b: 2} => "aaa", "a" => Object {a: 1, b: 2}}
    
    // map.has(key);//查找某一项,返回布尔值
    
    console.log(map.has('abc'));//false
    
    // map.clear();//删除所有项
    
    map.clear();
    console.log(map);//Map(0) {}

    循环map数据结构:

    let map = new Map();
    let json = {
        a:1,
        b:2
    }
    map.set('abc','123');
    map.set(json,'aaa');
    map.set('a',json);
    // 循环map
    for(let [key,value] of map){//默认entries
        console.log(key,value);
        /*abc 123
        Object {a: 1, b: 2} "aaa"
        Object {a: 1, b: 2}*/
    }
    for(let key of map.keys()){}
    for(let value of map.values()){}
    for(let [key,value] of map.entries()){}
    map.forEach((value,key)=>{
        console.log(key,value);
        /*abc 123
        Object {a: 1, b: 2} "aaa"
        Object {a: 1, b: 2}*/
    });

    5.1WeakMap数据结构:类似json,但是json的键(key)只能是字符串,而WeakMap的key只能是对象

    使用:

    // WeakMap使用
    let wmap = new WeakMap();
    let json = {
        a:1,
        b:2
    }
    wmap.set(json,'123');
    console.log(wmap);//WeakMap {Object {a: 1, b: 2} => "123"}

    总结:

    1.Set  里面是数组,不能重复,没有key(下标),没有get方法

    2.Map 对json功能增强,key可以是任意类型值

    6.数字变化和Math新增的东西

    6.1数字变化(数值变化)

    1.进制:

    // 二进制:(binary)
    let a = 0b010101;
    console.log(a);//21
    // 八进制:(Octal)
    let b = 0o652;
    console.log(b);//426
    // 十六进制:(Hexadecimal)
    let c = 0xabc;
    console.log(c);//2748

    2.数值判断

    // 数字变化
    let a = 12;
    // Number.isNaN:判断是否为NaN
    console.log(Number.isNaN(a));//false
    // Number.isFinite:判断是否是数字
    let b = 'aaa';
    console.log(Number.isFinite(b));//fasle
    // Number.isInteger:判断是否是整数
    let c = 12.12;
    console.log(Number.isInteger(c));//false
    console.log(Number.isInteger(a));//true
    // Number.parseInt():将一个数据转换成整数
    console.log(Number.parseInt(2.5));
    // Number.parseFloat():将一个数据转换成浮点数
    console.log(Number.parseFloat("13.5526"));//13.5526
    // Number.isSafeInteger():判断是否是安全整数
    /* 安全整数:-(2^53-1)到(2^53-1) */
    console.log(Number.isSafeInteger(-(2**53)));//false
    console.log(Number.isSafeInteger(-(2**53-1)));//true
    console.log(Number.isSafeInteger((2**53)));//false
    console.log(Number.isSafeInteger((2**53-1)));//true
    // Number.MAX_SAFE_INTEGER:最大安全整数
    console.log(Number.MAX_SAFE_INTEGER);//9007199254740991
    // Number.MIN_SAFE_INTEGER:最小安全整数
    console.log(Number.MIN_SAFE_INTEGER);//-9007199254740991

    6.2Math新增的东西

    // Math新增的东西
    // Math.trunc():截取数字整数部分
    console.log(Math.trunc(4.6));//4
    // Math.sign():判断一个数是正数、负数、0
    console.log(Math.sign(-5));//-1
    console.log(Math.sign(5));//1
    console.log(Math.sign(0));//0
    console.log(Math.sign(-0));//-0
    console.log(Math.sign('abc'));//NaN
    // Math.cbrt():计算一个数的立方根
    console.log(Math.cbrt(27));//3
    // ...等等

    7.ES2018(ES9)新增的东西

    7.1命名捕获(用于正则匹配)

    语法:(?<名字>)

    以前写正则,要把捕获到的数据赋给变量,都是这么写的

    let today = "2019-05-03";
    let reg = /(d{4})-(d{2})-(d{2})/;
    let dateArr = today.match(reg);
    let [full,year,month,day,...more] = dateArr;
    console.log(year,month,day);//2019 05 03

    现在,我们可以这么写:

    let today = "2019-05-03";
    let reg = /(?<year>d{4})-(?<month>d{2})-(?<day>d{2})/;//建议在Chrome浏览器下测试,别的浏览器可能会报错。
    let {year,month,day} = today.match(reg).groups;
    console.log(year,month,day);//2019 05 03

    7.2反向引用命名捕获

    1.反向引用以前写法:

    (1)1 2(字符串写法)    (2)$1 $2(str.replace()方法写法)

    语法:k<名字>

    如果要匹配和前面组相同的多个,可以这么写

    // 匹配:"monday-monday"
    // let reg = /^(?<m>monday)-k<m>$/;
    // let str = 'a-a';
    // let str2 = 'm-m';
    // let str3 = 'monday-monday';
    // console.log(reg.test(str));//false
    // console.log(reg.test(str2));//false
    // console.log(reg.test(str3));//true
    
    // 匹配:"monday-monday-monday"
    let reg = /^(?<m>monday)-k<m>-1$/;//或者let reg = /^(?<m>monday)-k<m>-k<m>$/;
    let str = 'a-a';
    let str2 = 'm-m';
    let str3 = 'monday-monday';
    let str4 = 'monday-monday-monday';
    console.log(reg.test(str));//false
    console.log(reg.test(str2));//false
    console.log(reg.test(str3));//false
    console.log(reg.test(str4));//true

    2.替换:$<名字>

    例如:正则转换日期格式:

    let str = '2019-05-03';
    let reg = /(?<year>d{4})-(?<month>d{2})-(?<day>d{2})/;
    
    let str1 = str.replace(reg,'$<day>/$<month>/$<year>');
    console.log(str);//2019-05-03
    console.log(str1);//03/05/2019

    结合回调函数:

    let str = '2019-05-03';
    let reg = /(?<year>d{4})-(?<month>d{2})-(?<day>d{2})/;
    
    let str1 = str.replace(reg,(...args)=>{
        // console.log(args);
        let {year,month,day} = args[args.length-1];
        return `${day}/${month}/${year}`;
    });
    console.log(str1);//03/05/2019

    7.3dotAll模式(用s)来表示:匹配任意东西

    之前,如果用正则匹配任意东西,用‘.’来匹配,但不包括 ,所以之前如果匹配 之类的东西,是这么写的

    let reg = /^w+.w+$/m;//注:在结尾处加m表示多行模式
    let str = 'turn-
    off';
    console.log(reg.test(str));//true

    但是如果匹配一些别的文字,比如换行符’ ‘,会匹配失败

    let reg = /^w+.w+$/m;
    let str = 'turn
    off';
    console.log(reg.test(str));//false

    现在可以用dotAll模式来匹配(结尾处加s即可):

    let reg = /^w+.w+$/s;//加s表示为dotAll模式
    let str = 'turn
    off';
    console.log(reg.test(str));//true

    7.3标签函数

    定义:和定义普通函数一样

    function fn(){
    
    }

    调用:

    fn();//这样调用就是普通函数
    fn`aaa`;//标签函数的调用

    Demo:

    function fn(args){
        return args[0].toUpperCase();//将第一个参数转为大写
    }
    console.log(fn`panda`);//调用标签函数

    7.4Proxy代理(扩展或增强对象的一些功能)

    作用:比如vue中的拦截,预警、上报、扩展功能、统计、增强对象等等;proxy是设计模式的一种,叫做代理模式。

    语法:new Proxy(target,handler),target为被代理的对象,handler对代理的对象做什么操作

    let obj = {//此对象不暴露给外部
        name:'jack'
    };
    let newObj = new Proxy(obj,{//此对象是暴露给外部的obj
        get(target,property){
            // console.log(target,property);
            // 在访问属性之前做一些操作
            console.log(`您访问了${property}属性`);
            return target[property];
        }
    }
    );
    console.log(newObj.name);//您访问了name属性 jack

    proxy对象的get(target,property):简单封装创建DOM元素的方法:

    /* 使用proxy对象简单封装创建DOM元素的方法 */
    const DOM = new Proxy({},{
        get(target,property){
            // console.log(target,property);
            return function(attr={},...children){
                // console.log(attr,children);
                let el = document.createElement(property);
                for(key of Object.keys(attr)){
                    el.setAttribute(key,attr[key]);
                }
                for(child of Object.values(children)){
                    if(typeof child == 'string'){
                        child = document.createTextNode(child);
                    }
                    el.appendChild(child);
                }
                return el;
            }
        }
    });
    let oDiv = DOM.div(
        {id:'div1'},'我是div','哈哈哈',
        DOM.a({href:'http://www.baidu.com'},'访问百度'),
        DOM.ul({},
            DOM.li({},'1111'),
            DOM.li({},'2222'),
            DOM.li({},'3333'),
            DOM.li({},'4444')
        )
    );
    window.onload = function(){
        document.body.appendChild(oDiv);
    }

    proxy对象的set(target,prop,value):检测设置年龄是否达到要求

    let obj = new Proxy({},{
        set(target,prop,value){
            // console.log(target,prop,value);
            if(prop == 'age'){
                if(!Number.isInteger(value)){
                    throw new TypeError('年龄必须为整数');
                }
                if(value>200){
                    throw new RangeError('年龄超标了,必须小于200岁');
                }
            }
            target[prop]=value;
        }
    });
    obj.a = 123;
    obj.name = 'pilot';
    console.log(obj);
    obj.age = 201;

    proxy对象的deleteProperty(target,property):删除对象属性之前,显示提示信息

    let json = {
        a:1,
        b:2
    }
    let newJson = new Proxy(json,{
        deleteProperty(target,property){
            console.log(`您要删除${property}属性`);
            delete target[property];
        }
    });
    delete newJson.a;
    console.log(newJson);

    proxy对象的has(target,property):

    let json = {
        a:1,
        b:2
    }
    let newJson = new Proxy(json,{
        has(target,property){
            console.log(`判断是否存在调用has方法`);
            return property in target;
        }
    });
    console.log('a' in newJson);//true
    console.log(newJson);

    proxy对象的apply():

    function fn(){
        return '我是一个函数';
    }
    let newFn = new Proxy(fn,{
        apply(){
            return '函数么?';
        }
    });
    console.log(newFn());

    apply结合reflect()来使用:

    function sum(a,b){
        return a+b;
    }
    let newSum = new Proxy(sum,{
        apply(target,context,args){
            // console.log(target,context,args);
            //console.log(...arguments);
            // return Reflect.apply(...arguments);//8
            return Reflect.apply(...arguments)**2;//64
        }
    });
    console.log(newSum(3,5));

    7.5Reflect反射:类似fn.call()、fn.apply()

    定义:Reflect.apply(调用的函数,this指向,参数数组)

    调用:

    // console.log(Math.ceil(5.2));//6
    let res = Reflect.apply(Math.ceil,null,[6.8]);
    console.log(res);//7

    检测对象的某一项属性是否存在:

    console.log(Reflect.has(Object,'assign'));//true

    删除对象的某一项属性:

    let json = {a:1,b:2};
    Reflect.deleteProperty(json,'a');
    console.log(json);//{b: 2}

    ---------------------END---------------------

    到这也就全部都完了,ES6以及ESNext的一些东西,下面附上其他俩个部分的地址,感谢观看!

    javascript的ES6学习总结(第一部分)

    javascript的ES6学习总结(第二部分)

  • 相关阅读:
    bootstrap class sr-only 什么意思?
    PHP 中的文本截取分析之效率
    FastAdmin 升级后出现 is already in use
    FastAdmin 环境变量 env 配置
    Nginx 服务器伪静态配置不当造成 Access denied
    笔记:明确认识
    进程通信(socket)
    进程间通信(了解)
    c++ 继承,组合
    c++ 类初始化
  • 原文地址:https://www.cnblogs.com/abc-x/p/10799583.html
Copyright © 2020-2023  润新知