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);//
(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);//
- // 八进制:(Octal)
- let b = 0o652;
- console.log(b);//
- // 十六进制:(Hexadecimal)
- let c = 0xabc;
- console.log(c);//
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);//
- // Number.MIN_SAFE_INTEGER:最小安全整数
- console.log(Number.MIN_SAFE_INTEGER);//-9007199254740991
6.2Math新增的东西
- // Math新增的东西
- // Math.trunc():截取数字整数部分
- console.log(Math.trunc(4.6));//
- // Math.sign():判断一个数是正数、负数、0
- console.log(Math.sign(-5));//-1
- console.log(Math.sign(5));//
- console.log(Math.sign(0));//
- console.log(Math.sign(-0));//-0
- console.log(Math.sign('abc'));//NaN
- // Math.cbrt():计算一个数的立方根
- console.log(Math.cbrt(27));//
- // ...等等
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;//
- }
- });
- 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);//
检测对象的某一项属性是否存在:
- 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学习总结(第二部分)
1.数组循环 介绍数组循环之前,先回顾一下ES5数组的循环 (1)数组遍历(代替普通的for):arr.forEach(callback(val,index,arr){todo}) //val是数组的 ...
- javascript的ES6学习总结(第一部分)
ES6(ESNext学习总结——第一部分) ES6, 全称 ECMAScript 6.0 ,是 JavaScript 的下一个版本标准,2015.06 发版. ECMA每年6月份,发布一个版本 201 ...
- ES6学习笔记(三):教你用js面向对象思维来实现 tab栏增删改查功能
前两篇文章主要介绍了类和对象.类的继承,如果想了解更多理论请查阅<ES6学习笔记(一):轻松搞懂面向对象编程.类和对象>.<ES6学习笔记(二):教你玩转类的继承和类的对象>, ...
- Javascript oop深入学习笔记(三)--javascript中类的实现
一.类的实现机制 在javascript中可以使用function关键字来定义一个类.在函数内通过this指针引用的变量或则方法都会成为类的成员. function classDemo(){ var ...
- ES6学习笔记(三)
ES6加强了对Unicode的支持,并且扩展了字符串对象. 1.字符的Unicode表示法 JavaScript允许采用\uxxxx形式表示一个字符,其中"xxxx"表示字符的码点 ...
- JavaScript高级程序设计---学习笔记(三)
函数表达式 定义函数的方式有两种:一种是函数声明,另一种是函数表达式. 关于函数声明,它的一个重要特征就是函数声明提升,意思是在执行代码之前会先读取函数声明所以可以把函数声明放在调用它的语句后面. 而 ...
- ES6学习笔记(三):与迭代相关的新东东
Symbol 概念 Symbol:一种新的原始数据类型,表示独一无二的值. 注意:Symbol函数的参数只是表示对当前Symbol值的描述,因此相同参数的Symbol函数的返回值是不相等的. // 没 ...
- JavaScript高级程序设计学习笔记第三章--基本概念
一.标识符: 1.区分大小写 2.命名规则: 第一个字符必须是一个字母.下划线(_)或一个美元符号($) 其他字符可以是字母.下划线.美元符号或数字 标识符中的字母也可以包含扩展的 ASCII 或 U ...
- ES6学习笔记(三)字符串的扩展
ES6 加强了对 Unicode 的支持,并且扩展了字符串对象. 1.字符的Unicode表示法 JavaScript 允许采用\uxxxx形式表示一个字符,其中xxxx表示字符的 Unicode 码 ...
随机推荐
- python之turtle画蚊香
原理:利用turtle绘制圆形,并使圆半径逐步增加 代码如下: import turtle turtle.pensize(30) for i in range(30): turtle.circle(i ...
- win10 下安装zookeeper+Kafka 的详细步骤(2)
Win10 下要使用Kafka需要经过以下三个步骤: 1.安装JDK(需要安装依赖java JDK) 2.安装zookeeper(资源协调,分配管理) 3.使用Kafka开发 ============ ...
- EasyCode实现数据库到Swagger全自动化
简介 EasyCode是基于IntelliJ IDEA开发的代码生成插件,通过自定义生成模板可以完成定制化的 Mapper Service Controller 生成,结合数据库 Comment还可以 ...
- 使用Cap解决.Netcore分布式事务
一.什么是Cap CAP 是一个基于 .NET Standard 的 C# 库,它是一种处理分布式事务的解决方案,同样具有 EventBus 的功能,它具有轻量级.易使用.高性能等特点. 在我们 ...
- day20191106
笔记: 一.#{}和${}的区别是什么 1)#{}是预编译处理,${}是字符串替换.2)Mybatis 在处理#{}时,会将 sql 中的#{}替换为?号,调用 PreparedStatement 的 ...
- Netty学习——protoc的新手使用流程
Netty学习——protoc的新手使用流程 关于学习的内容笔记,记下来的东西等于又过了一次脑子,记录的更深刻一些. 1. 使用IDEA创建.proto文件,软件会提示你安装相应的语法插件 安装成功之 ...
- 用launchscreen.storyboard适配启动图方法(二)
背景 之前有写一篇实现方式比较简单的随笔用launchscreen.storyboard适配启动图方法,顺便在评论区提了一下用autolayout适配启动图的思路,现把思路和流程记录下来. 思路 整体 ...
- 洛谷 题解 P1842 【奶牛玩杂技】
本蒟蒻又双叒叕被爆踩辣! Solution: 我们先看数据,50000,那么O(n)或者O(n log(n))是可以过的,非严格O(n * sqrt(n))要卡卡常,说不定也可以过. 那么什么算法可以 ...
- luogu P1168 中位数 |树状数组+二分
题目描述 给出一个长度为NN的非负整数序列A_i,对于所有1 ≤ k ≤ (N + 1) / 21≤k≤(N+1)/2,输出A_1, A_3, -, A_2k - 1的中位数.即前1,3,5,-个数的 ...
- dubbo 订阅 RPC 服务
Dubbo 订阅 RPC 服务 建立消费者者项目 pom.xml <?xml version="1.0" encoding="UTF-8"?> &l ...