{
let regex = new RegExp('xyz','i');
let regex2 = new RegExp(/xyz/i); //上述两个例子是ES5
console.log(regex.test('xyz123'),regex2.test('xyz123'));
//输出结果为两个true
// 在ES5的正则中,类似"/xyz/i"这样的格式只能添加一个修饰符,比如这里的i
let regex3 = new RegExp(/xyz/ig,'i');
console.log(regex3.flags);
//flags是ES6新引入的用来获取正则对象的
//输出结果是i
//后面的参数回覆盖掉前面的
}
ES6引入的新正则修饰符y
{
let s = 'bbb_bb_b'
let a1 = /b+/g;
let a2 = /b+/y;
console.log('one',a1.exec(s),a2.exec(s)); //两种修饰符都能匹配到bbb
console.log('two',a1.exec(s),a2.exec(s)); //g能匹配到bb,y不能
//g是贪婪模式,不要求第一个字符匹配成功,一旦字符串中匹配的内容就可以匹配成功;但是如果使用y,假如前面的字符无法匹配,那么最后的结果就无法匹配上
console.log(a1.sticky,a2.sticky); //检测是否使用修饰符y匹配
}
ES6引入的新正则修饰符u
{
console.log('u-1',/^\uD83D/.test('\uD83D\uDC2A'));
console.log('u-2',/^\uD83D/u.test('\uD83D\uDC2A'));
//最后的结果是第一个匹配成功,第二个失败;原因在于当加入u参数后,系统认为'\uD83D\uDC2A'为一个字符
console.log(/\u{61}/.test('a'));
console.log(/\u{61}/u.test('a'));
//最终结果是第一个false,第二个true;如果用户不加入u修饰,那么系统不会识别编码
// u修饰符还可以补充ES5中正则匹配的缺陷(当Unicode值大于FFFF时无法匹配)
}
如果要表示编码大于FFFF
的字符,也就是大于两个字节,需要补充上{ }
,例如:
console.log('s',
\u{20BB7});
结果:𠮷
注意这个字符的length属性就是2
let s='𠮷';
console.log('length',s.length);
console.log('0',s.charAt(0));
console.log('1',s.charAt(1));
console.log('at0',s.charCodeAt(0));
console.log('at1',s.charCodeAt(1));
//ES5
let s1='𠮷a';
console.log('length',s1.length);
console.log('code0',s1.codePointAt(0));
console.log('code0',s1.codePointAt(0).toString(16));
console.log('code1',s1.codePointAt(1));
console.log('code2',s1.codePointAt(2));
//ES6
console.log(String.fromCharCode('0x20bb7')); //ES5
console.log(String.fromCodePoint('0x20bb7')); //ES6
let str = '\u{20bb7}abc';
for(let i=0;i<str.length;i++)
console.log('ES5',str[i]);
for(let code of str)
console.log('ES6',code);
//ES6的字符串操作接口
{
let str = "string";
console.log("includes",str.includes("c"));
console.log("start",str.startWith('str'));
console.log('end',str.endWith('ng'));
}
{
left str = 'abc';
console.log(str.repeat(2));
}
{
let name = "list";
let info = "hello world";
let m=`i am ${name},${info}`;
console.log(m);
}
{
console.log('1',padStart(2,'0'));
//输出01
console.log('1',padEnd(2,'0'));
//输出10
}
{
let user = {
name : 'list',
info : 'hello world'
};
console.log(abc`i am ${user.name},${user.info}`);
function abc(s,v1,v2){
console.log(s,v1,v2);
return s+v1+v2;
}
}
{
console.log(0b11001); //二进制
console.log(0o602); //八进制
}
判断是否有穷尽的api Number.isFinte()
and 判断是否为数字的apiNumber.isNaN()
{
console.log('10',Number.isFinite(10)); //true
console.log('NaN',Number.isFinite(NaN)); //false
console.log('1/0',Number.isFinite('true'/0)); //false
console.log(Number.isNaN(NaN));
}
判断是否为整数的api Number.isInteger()
{
console.log('10',Number.isInteger(10)); //true
console.log('10',Number.isInteger(10.0)); //true
console.log('10',Number.isInteger(10.1)); //false
}
注意,传入的参数是x.0也认为是整数,但是小数点后不是0那么就不认为是整数
向下取整api Math.trunc()
{
console.log(Math.trunc(3.2)); //3
}
判断正负数apiMath.sign()
{
console.log(Math.sign(-3)); //-1,表示为负数
console.log(Math.sign(0)); //0,表示为0
console.log(Math.sign(3)); //1,表示为正数
console.log(Math.sign('3')); //1,由数字组成的字符串会转换为数字
console.log(Math.sign(‘te')); //NaN
}
立方根api Math.cbrt()
创建数组api Array.of()
{
let arr = Array.of(1,2,3,4);
console.log(arr); //[1,2,3,4]
}
集合转义为数组api Array.from()
{
let p = document.querySelectorAll('p');
left pArr = Array.from(p);
pArr.forEach(function(item){
console.log(item.textContent);
});
console.log(Array.from([1,2,3],function(item){
return item*2
}));
//数组映射:[2,4,6]
}
数组元素替换api Array.fill()
{
console.log([1,'a',undefined].fill(2)); //[2,2,2]
console.log(['a','b','c'].fill(1,2,3)); //["a","b",1]
console.log(['a','b','c','d'].fill(1,2,4)); //["a", "b", 1, 1]
}
返回数组索引api Array.keys()
and 索引对应值api Array.values()
and 同时打印索引和对应值的api Array.entries()
{
for(let index of ['a','b','c'].keys())
console.log(index);
//0 1 2
for(let value of ['a','b','c'].values())
console.log(value);
//a b c
//注意 chrome上values有兼容问题
for(let [index,value] of ['a','b','c'].entries())
console.log(index,value);
let test = {k:12,o:34};
for(let [key,value] of Object.entries(test)){
console.log([key,value]);
}
}
数组内元素值覆盖api Array.copyWithin()
{
console.log([1,2,3,4,5].copyWithin(0,3,4));
//[4,2,3,4,5]
console.log([1,2,3,4,5].copyWithin(1,2,4));
//[1, 3, 4, 4, 5]
}
数组内查找符合条件的元素api Array.find()
{
console.log([1,2,3,4,5,6].find(function(item){
return item>3;
}));
//4,注意只返回第一个符合条件的元素
//如果是返回第一个符合条件的元素下标则使用findIndex
//如果需要返回全部符合条件的元素,就用filter
//补充,前面提到的includes可以判断数组内是否有符合条件的元素
console.log([1,2,NaN.includes(NaN)); //true
}
{
function test(x,y='world'){
console.log('默认值',x,y);
}
test('hello'); //hello.world
test('hello','ES6'); //hello,ES6
}
注意在函数默认值参数后面不能增加非默认值的参数,比如不能有 y='a',x
这样的形式,但是可以有 y='a',x='s'
{
let x = 'test';
function test1(x,y=x){
console.log(x,y);
}
test1('new'); //new,new
function test2(c,y=x){
console.log(c,y);
}
test2('new'); //new,test
}
将不确定的输入参数转换为数组。
注意,rest参数后面不能加任何参数
{
function test3(...arg){
for(let v of arg){
console.log(v);
}
}
test3(1,2,'a');
}
{
console.log(...[1,2,3]);
//将数组离散化,和前面的rest参数将离散化内容数组化相反
}
格式:函数名=参数=返回值
{
let arrow = v => v*2;
console.log(arrow(3));
//6
let arrow2 = () => 2;
//2
}
{
function tail(x){
console.log(x);
}
function fx(x){
return tail(x);
}
fx(12); //12
}
//属性
{
let es5 = {
o : o,
k : k
};
let es6 = {
o,
k
};
console.log(es5,es6);
//方法
let es5Method = {
hello : function(){
console.log('hello');
}
};
let es6Method = {
hello(){
console.log('hello');
}
};
//属性表达式
let a = 'b';
let es5Obj = {
a : 'c',
b : 'c'
};
let es6Obj = {
[a] : 'c'
}
console.log(es5Obj,es6Obj);
//{a: "c", b: "c"} {b: "c"}
}
判断两个对象是否全等,等价于 ===
console.log(Object.is('abc','abc');
浅拷贝
console.log(Object.assign({a:'a'},{b:'b'}));
//{a: "a", b: "b"}
Symbol声明的对象是独一无二的
let a1=Symbol();
let a2 =Symbol();
console.log(a1===a2);
//false
//还原对象:for
let a3=Symbol.for('a3');
let a4=Symbol.for('a3');
console.log(a3===a4);
//true
Symbol对象的作用:可以避免前一个对象被后面一个同名的对象覆盖
{
let a1 = Symbol.for('abc');
let obj = {
[a1] : '123',
'abc' : 345,
'c' : 678
};
console.log(obj);
//{abc: 345, c: 678, Symbol(abc): "123"}
}
注意,当对象中使用Symbol作为key值的时候,通过for-in或of都是不可获取它的属性的
{
let a1 = Symbol.for('abc');
let obj = {
[a1] : '123',
'abc' : 345,
'c' : 678
};
console.log(obj);
for(let [key,value] of Object.entries(obj)){
console.log(key+":"+value);
//abc:345 c:678 undefined
}
Object.getOwnPropertySymbols(obj).forEach(function(item){
console.log(obj[item]);
})
//123
Reflect.ownKeys(obj).forEach(function(item){
console.log(item,obj[item]);
})
//可以获取Symbol(abc) "123"
}
{
let list = new Set();
list.add(1);
list.add(2);
console.log(list.size);
//2
let a = [1,2,3];
let b = new Set(a);
console.log(b.size);
//3
}
添加重复的set数据是无法实现的,利用这个特性可以实现去重
{
let a = [1,2,3,1,2];
let b = new Set(a);
console.log(b);
//Set(3) {1, 2, 3}
}
Set的几个api
{
let arr = ['add','delete','clear','has'];
let list = new Set(arr);
console.log(list.has(’add'));
console.log(list.delete('add'),list);
list.clear();
console.log(list);
}
遍历set:
let arr = ['add','delete','clear','has'];
let list = new Set(arr);
for(let key of list.keys()){
console.lof(key);
}
for(let value of list.values()){
console.lof(value);
}
for(let [key,calue] of list.entries()){
console.lof(key,value);
}
list.forEach(function(item){console.log(item);});
和Set的区分:
- 不能遍历
- 支持的数据类型不一样:WeakSet的元素只能是对象
- WeakSet对象都是弱引用,不会检测对象是否在其他地方引用过,所以不会和垃圾回收机制挂钩
- 一些属性和方法不同
map的一个特点是可以用任何数据作key值
{
let map1 = new Map();
let arr = ['123'];
map1.set(arr,456); //注意map添加数据是用set方法
console.log(map1,map1.get(arr));
//Map(1) {Array(1) => 456} 456
let map2 = new Map([['a',123],['b',456]]);
console.log(map2);
//Map(2) {"a" => 123, "b" => 456}
console.log(map2.size);
console.log(map2.delete('a'),map2);
console.log(map2.clear(),map2);
}
Set和WeakSet的关系等同map和WeakMap
//map和数组array对比
{
let map = new Map();
let array = [];
//增
map.set('t',1);
array.push({t:1});
console.log('map-array',map.array);
//查
let map_exist = map.has('t');
let array_exist = array.find(item=>item.t);
console.log(map_exist,array_exist);
//改
map.set('t',2);
array.forEach(item=>item.t?item.t=2:'');
console.log(map,array);
//删
map.delete('t');
let index = array.findIndex(item=>item.t);
array.splice(index,1);
console.log(map,array);
}
//set和数组array对比
{
let set = new Set();
let array = [];
//增
set.add({t:1});
array.push({t:1});
console.log(set,array);
//查
let set_exist = set.has({t:1});
let array_exist = array.find(item=>item.t);
console.log(set_exist,array_exist);
//改
set.forEach(item=>item.t?item.t=2:'');
array.forEach(item=>item.t?item.t=2:'');
console.log(set,array);
//删
set.forEach(item=>item.t?set.delete(item):'');
let index = array.findIndex(item=>item.t);
array.splice(index,1);
console.log(set,array);
}
//map、set、object对比
{
let item = {t:1};
let map = new Map();
let set = new Set();
let obj = {};
//增
map.set('t',1);
set.add(item);
obj['t'] = 1;
//查
console.log({
map_exis : map.has('t');
set_exist : set.has(item);
obj_exist : 't' in obj
})
//改
map.set('t',2);
item.t = 2;
obj['t'] = 2;
//删
map.delete('t');
set.delete(item);
delete obj['t'];
}
总结:
优先使用map,如果要考虑到数据的唯一性,那么优先考虑set
Proxy和Reflect的方法是一样的
{
let obj = {
time : '2017-2-1',
name : 'ES6',
_t : 123
};
let monitor = new Proxy(obj,{
//拦截对象属性的读取
get(target,key){
return target[key].replace('2017','2018')
},
//拦截对象设置属性
set(target,key,value){
if(key=='name'){
return target[key] = value;
}else{
return target[key];
}
},
//拦截key in object操作
has(target,key){
if(key=='name'){
return target[key];
}else{
return false;
}
}
//删除
deleteProperty(target,key){
if(key.indexOf('_') > -1){
delete target[key];
return true;
}else{
return target[key];
}
},
//拦截object.key,object.getOwnPropetySymbols,Object.getOwnPropertyNames
ownKeys(target){
return Object.keys(target).filter(item=>item!='time')
}
});
console.log(Object.keys(monitor));
console.log(monitor.time); //2018-2-1
monitor.name = 'ES';
console.log(monitor.name); //ES
console.log('name' in monitor); //true
delete monitor.time;
console.log(monitor); //没有删除time属性
delete monitor._t;
console.log(monitor); //删除了_t
}
{
class Parent{
constructor(name='mooc'){
this.name = name;
}
}
let v_parent = new Parent('v);
console.log(v_parent.name); //mooc
}
//类与构造函数创建
{
class Parent{
constructor(name='mooc'){
this.name = name;
}
}
class Child extends Parent{}
console.log(new Child()); //mooc
}
//继承
{
class Parent{
constructor(name='mooc'){
this.name = name;
}
}
class Child extends Parent{
constructor(name='child'){
super(name); //在构造函数中使用super关键字,super必须放在第一行
this.type = 'child';
}
}
console.log(new Child(‘ES6’)); //ES6
}
//继承和修改
{
class Parent{
constructor(name='mooc'){
this.name = name;
}
get longName(){ //注意这不是方法,是属性
return 'mk' + this.name
}
set longName(value){
this.name = value;
}
}
let v = new Parent();
console.log(v.longName); //mkmooc
v.longName = 'hello';
console.log(v.longName); //mkhello
}
//继承
{
class Parent{
constructor(name='mooc'){
this.name = name;
}
static tell(){
console.log('tell');
}
}
Parent.tell(); //tell
}
//静态方法
{
class Parent{
constructor(name='mooc'){
this.name = name;
}
}
Parent.type = 'test';
console.log(Parent.type); //test
}
//静态属性
{
let pro = function(callback){
console.log('excute');
setTimeoout(function(){
callback && callback.call()
},2000);
};
pro(function(){
console.log('test1');
})
}
{
let pro = function(){
console.log('excute');
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve();
},2000);
})
};
pro().then(function(){
console.log('resolve');
},function(){
console.log('reject');
})
}
{
let pro = function(){
console.log('excute');
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve();
},2000);
})
};
pro()
.then(function(){
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve();
},2000);
});
})
.then(functionn(){
console.log('test');
})
}
{
let pro = function(num){
console.log('excute');
return new Promise(function(resolve,reject){
if(num>5){
resolve()
}else{
throw new Error('Error!');
}
})
}
pro(6).then(function(){
console.log('6');
}).catch(function(err){
console.log(err);
});
pro(2).then(function(){
console.log('2');
}).catch(function(err){
console.log(err);
});
}
实际案例使用:
有些情况下,网页需要加载出所有图片才添加到页面上
{
function loadImg(src){
return new Promise((resolve,reject)=>{
let img = document.createElement('img');
img.src = src;
img.onload = function(){
resolve(img);
}
img.onerror = function(){
reject(err);
}
})
}
function showImgs(imgs){
imgs.forEach(function(){
document.body.appendChild(img);
})
}
Promise.all([ //创建一个新Promise实例,当传入的所有Promise实例状态完成才记载新的Promise实例
loadImg("http://xxx");
loadImg("http://xxx");
loadImg("http://xxx");
]).then(showImgs)
}
有些情况,需要一张图片加载完成后就结束其他未加载内容的加载
{
function loadImg(src){
return new Promise((resolve,reject)=>{
let img = document.createElement('img');
img.src = src;
img.onload = function(){
resolve(img);
}
img.onerror = function(){
reject(err);
}
})
}
function showImgs(imgs){
imgs.forEach(function(){
document.body.appendChild(img);
})
}
Promise.race([
loadImg("http://xxx");
loadImg("http://xxx");
loadImg("http://xxx");
]).then(showImgs)
}
{
let arr = ['hello','world'];
let map = [Symbol.iterator]();
console.log(map.next());
console.log(map.next());
console.log(map.next());
}
{
let obj = {
start : [1,2,3],
end : [4,5,6],
[Symbol.iterator](){
let self = this;
let index = 0;
let arr = self.start.concat(self.end);
let len = arr.length;
return {
next(){
if(index<len){
return {
value : arr[index++],
done : false;
}
}else{
return {
value : arr[index++];
done : true
}
}
}
}
}
}
for(let key of obj){
console.log(key);
}
}
//创建有iterator接口的object
{
let tell = function* (){
yield 'a';
yield 'b';
return 'c';
};
let k = tell();
console.log(k.next()); //a
console.log(k.next()); //b
console.log(k.next()); //c
console.log(k.next()); //undefined
}
{
let obj = {};
obj[Symbol.iterator] = function* (){
yield 1;
yield 2;
yield 3;
}
for(let value of obj){
console.log(value);
}
}
{
let state = function* (){
while(1){
yield 'A';
yield 'B';
yield 'C';
}
}
let status = state();
console.log(status.next()); //A
console.log(status.next()); //B
console.log(status.next()); //C
console.log(status.next()); //A
console.log(status.next()); //B
console.log(status.next()); //C
}
{
let state = async function (){
while(1){
await 'A';
await 'B';
await 'C';
}
}
let status = state();
console.log(status.next()); //A
console.log(status.next()); //B
console.log(status.next()); //C
console.log(status.next()); //A
console.log(status.next()); //B
console.log(status.next()); //C
}
Generator的应用
抽奖活动:抽奖页面需要前后端一起配合,这里只是讲前端的
如果将抽奖剩余次数变量作为全局变量,首先是容易受污染,其次用户可能可以察觉并修改该变量
generator可以很好地实现
{
let draw = function(count){
console.log(`剩余${count}次`);
//这里是抽奖逻辑
}
let residue = function* (count){
while(count > 0){
count--;
yield draw(count);
}
}
let star = residue(5);
let btn = document.createElement('button');
btn.id = 'start';
btn.textContent = '抽奖';
document.body.appendChild(btn);
document.getElementById('start').addEventListener('click',function(){
star.next();
},false);
}
长轮询
{
let ajax = function* (){
yield new Promise(function(resolve,reject){
setTimeout(function(){ //模拟和后端通信
resolve({code:0}); //如果不是0,那么就一直间隔轮询
},200)
})
}
let pull = function(){
let generator = ajax();
let step = generator.next();
step.value.then(function(d){ //拿到d,代表后端数据
if(d.code!=0){ //拿到数据不是最新的
setTimeout(function(){
console.log('wait');
pull()
},1000);
}else{
console.log(d);
}
})
}
pull();
}
{
let readonly = function(target,name,descriptor){
descriptor.writable = false;
return descriptor;
};
class Test{
@readonly
time(){
return '2018-2-1'
}
}
let test = new Test();
console.log(test.time()); //2018-2-1
test.time = function(){
console.log('reset time');
};
console.log(test.time()); //报错
}
{
let typename = function(target,name,description){
target.myname = 'hello';
}
@typename
class Test{}
console.log(Test.myname); //hello
}
补充说明一个包含多种修饰器的第三方库:core-decorators ,可以通过npm安装
需要导出的模块(命为test.js):
export let A = 123;
export function test(){
console.log('test');
}
export class Hello{
test(){
console.log('class');
}
}
需要导入的模块:
import {A,test,Hello} from './test';
console.log(A,test,Hello);
或者:
import * as lesson from './test';
console.log(lesson.A);
//导出的模块:
let A = 123;
let test = function(){
console.log('test');
}
class Hello{
test(){
console.log('class');
}
}
export default {
A,
test,
Hello
}
//导入的模块:
import lesson from './test';