欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-07-05 14:19:33
1.ES6中的面向对象的类 1.1、定义类 在ES5中,我们写一个类,通常是这么写的 在ES6中,我们可以这样写 注意: (1).ES6里面Class没有提升(例如ES5中的函数有提升到顶部的作用) (2).ES6中的this,首先来看一下ES5中矫正this的几个方法 (2.1) fn.call( ......

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)来表示:匹配任意东西

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

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

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

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

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

let reg = /^\w+.\w+$/s;//加s表示为dotall模式
let str = 'turn\noff';
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的一些东西,感谢观看!