1.【正则扩展】
// ES5 声明一个正则表达式
let regex = new RegExp("xyz",'i'); //方式1 , “i”修饰符是不区分大小写
let regex2 = new RegExp(/xyz/i); // 方式2
console.log(regex.test('xyz123'),regex2.test('xyz123')); // true true
// ES6
let regex3 = new RegExp(/xyz/ig,"i"); // 后面的"i"的修饰符 会覆盖 前面 正则表达式后面的修饰符
console.log(regex3.flags); // i
修饰符:
// es5
// g修饰符:全局匹配,但是当第二次匹配的时候,不强调是从 紧跟着 第一次匹配结果的下一个字符,只要找到匹配的字符即可
// y修饰符:全局匹配,但是当第二次匹配的时候,必须是紧跟着 第一次匹配结果的下一个字符
let s = 'bbb_bb_b';
let a1 = /b+/g;
let a2 = /b+/y;
console.log('one',a1.exec(s),a2.exec(s));
//one [ 'bbb', index: 0, input: 'bbb_bb_b', groups: undefined ] [ 'bbb', index: 0, input: 'bbb_bb_b', groups: undefined]
console.log('two',a1.exec(s),a2.exec(s)); // two [ 'bb', index: 4, input: 'bbb_bb_b', groups: undefined ] null
// 判断是否使用 y 修饰符
console.log(a1.sticky , a2.sticky) // false true
// u修饰符 unicode编码,匹配的字符中出现大于两个字节长度的字符,要使用u修饰符
// 对于 “.” 修饰符可以匹配到任何字符,前提条件是 字符串长度小于两个字节;
// 对于换行,回车,行分割,段分割符,"." 修饰符也是不能识别的
console.log("u-1",/^\uD83D/.test('\uD83D\uDC2A')); // u-1 true \uD83D\uDC2A 相当于是两个
console.log("u-2",/^\uD83D/u.test('\uD83D\uDC2A')); // u-2 false \uD83D\uDC2A这个 是 Unicode编码中一个字符,所以匹配不成功
console.log(/\u{61}/.test('a')); // false
console.log(/\u{61}/u.test('a')); //true 可以识别 Unicode编码 {}
console.log("s",`\u{20BB7}`); // s ?
2.【Symbol】
Symbol这个 数据类型,直接使用Symbol()声明,声明的变量是独一无二的
let a1 = Symbol();
let a2 = Symbol();
console.log(a1 === a2); // false
// 生成一个独一无二的值,但是 Symbol.for(key),先检查这个值是否 全局配置过
// 如果全局配置过 就返回 配置的值
let a3 =Symbol.for('a3');
let a4 = Symbol.for('a3');
console.log(a4); // Symbol(a3)
console.log(a3 === a4); // true
let a = Symbol.for('abc');
let obj = {
[a]:'123',
'abc':234,
'd':345
}
console.log('obj',obj); // obj { abc: 234, d: 345, [Symbol(abc)]: '123' }
// 普通的 for...of...遍历得不到 Symbol 定义的 key-value
for(let [key,value] of Object.entries(obj)){
console.log('let of',key,value); // let of abc 234 let of d 345
}
// 拿到Symbol声明的 key
Object.getOwnPropertySymbols(obj).forEach( item =>{
console.log(obj[item]); //123
})
// 拿到对象中所有的 key ,包括 Symbol定义的key
Reflect.ownKeys(obj).forEach( item =>{
console.log('ownkeys',item,obj[item]);
// ownkeys abc 234
// ownkeys d 345
// ownkeys Symbol(abc) 123
})
3.【Promise】
处理 异步操作,JS中(包括node.js)处理异步操作的方式有四种:回调函数,事件监听,Promise,RXJS
回调:
let ajax = function (callback) {
setTimeout( ()=>{
callback&&callback.call()
},1000);
console.log("执行")
}
ajax(()=>{
console.log('回调') // 执行 回调(1秒后输出)
})
基于Promise构造函数创建的实例:
let ajax = function(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve()
},1000)
})
}
// 实现方式
ajax().then(()=>{
console.log('promise','timeout') // (控制台1秒之后输出) promise timeout
})
连续返回2个Promise实例:
ajax()
.then(()=>{
console.log("1")
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve()
},2000)
})
})
.then(()=>{
console.log('timeOut3') // 执行 (1秒后输出)1 (2秒后输出) timeOut3,
})
Promise使用 catch 处理 error:
let ajax = function(num){
return new Promise((resolve,reject)=>{
if(num>5){
resolve()
}else{
throw new Error("出错了")
}
})
}
ajax(8).then(()=>{
console.log("log",6); // log 6
}).catch(err=>{
console.log('catch',err);
})
应用小场景:基于Promise实现一个 红绿灯 事件的跳转
let traffic = function(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve()
},3000)
})
}
setInterval(()=>{
traffic().then(()=>{
console.log("1","红灯");
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve()
},2000)
})
}).then(()=>{
console.log("2","黄灯");
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve()
},1000)
})
}).then(()=>{
console.log("3","绿灯");
})
}, 6000);
这里利用setInterval()定时器实现了 6秒一个红黄绿轮回,红灯持续2秒过后黄灯,黄灯持续1秒后绿灯,绿灯持续3秒后又是红灯,一直这样下去。。。
【Promise.all() && Promise.race()】
Promise.all([
// ...多个 Promise 实例加载完了之后,返回一个promise 实例,才能执行 then()
]).then()
// 先到先得,先加载到的图片就先显示
Promise.race([
// ...多个promise实例中,只要有一个实例状态改变了,race的Promise就会响应
]).then()
4.【Proxy && Reflect】
let obj = {
time:'2017-03-11',
name:'net',
_r:123
}
new Proxy()声明一个代理,代理obj(target === obj)
let moniter = new Proxy(obj,{
// 拦截对象属性的读取
get(target,key){
if( key == "time"){
return target[key].replace("2017","2018");
}else{
return target[key];
}
},
// 拦截对象的设置属性
set(target,key ,value){
if(key === "name"){
return target[key] = value;
}else{
return target[key];
}
}
})
console.log('get',moniter.time); // get 2018-03-11 ,这里通过moniter 代理 obj 读取 time,针对读取的操作,代理在读取中间做了一些操作,将 原有的time = 2017,替代为2018
// 设置属性
moniter.time = "2019";
moniter.name = "zhoushiqin";
console.log("set",moniter.time,moniter.name); // set 2018-03-11 zhoushiqin
console.log("set",obj); // set { time: '2017-03-11', name: 'zhoushiqin', _r: 123 }
Reflect和Proxy ,他们的对象使用方法一样,就是在创建实例的时候有所区别,Reflect是直接使用:Reflect(),Proxy需要 new 操作符 : new Proxy()
console.log("reflect" ,Reflect.get(obj,"name")); // reflect net
Reflect.set(obj ,"name" ,"han meimei");
console.log("reflect" ,obj); // reflect { time: '2017-03-11', name: 'han meimei', _r: 123 }
Proxy和Reflect的应用场景:数据类型的校验
// 设置 校验代理 target为代理的对象,validator 为校验规则
function validator( target,validator){
return new Proxy(target,{
_validator:validator,
set(target,key,value,proxy){
if(target.hasOwnProperty(key)){
let va = this._validator[key];
if(!!va(value)){
return Reflect.set(target,key,value,proxy);
}
return target[key] = value;
}else{
throw Error(`${key}不存在`)
}
}
})
}
// 校验规则
const personValidators = {
name(val){
return typeof val === 'string'
},
age(val){
return typeof val === "number" && val>18
}
}
// 创建实例
class Person{
constructor(name,age){
this.name = name;
this.age = age;
return validator(this,personValidators) // 这里的this就是Person创建的实例
}
}
const person = new Person('lilie',30);
console.info(person); // Person { name: 'lilie', age: 30 }
person.name = "zhoushiqin";
console.info(person); // Person { name: 'zhoushiqin', age: 30 }