一、let和const
es6之前有两个作用域:全局作用域、函数作用域
es6新增加了块作用域,也就是{}包起来的代码
function test() {
for (let i=1;i<3;i++){
console.log(i);
}
console.log(i);//error: i is not defined
}
为什么报错?因为es6强制开启了严格模式,变量未声明不能引用
let a=3;
let a=4;
报错,不能重复声明!
const PI=3.14;
定义常量,常量不能修改!也是有块作用域的!并且,声明的时候必须赋值!
const PI=3.14,
k={
a:1
};
k.b=3;
console.log(PI,k);
可以输出。是因为k是对象,是引用类型,返回的是对象存储内存的指针,发生了修改也可以输出。
const和let的唯一区别就是,const不可以被更改,所以当声明变量的时候,尤其是在声明容易被更改的全局变量的时候,尽量使用const。
- 更好的代码语义化,一眼看到就是常量。
- 另一个原因是因为JavaScript 编译器对const的优化要比let好,多使用const,有利于提高程序的运行效率。
- 所有的函数都应该设置为常量。
二、解构赋值
解构赋值的分类:数组结构赋值(左右都是数组)、对象结构赋值(左右都是对象)、字符串结构赋值(左数组、右字符串)、布尔值结构赋值、函数参数解构赋值(数组解构赋值在函数上的引用)、数值解构赋值
{
let a,b,rest;
[a, b]=[1,2];
console.log(a);//1
console.log(b);//2
}
{
let a,b,rest;
[a, b, ...rest]=[1,2,3,4,5,6];
console.log(a, b, rest);//1 2 [3,4,5,6]
}
{
let a,b;
({a, b}={a:1,b:2});
console.log(a, b);//1,2
}
{
let a,b,c,rest;
[a, b,c = 3]=[1,2];
console.log(a, b, c);//1 2 3
}
如果c没有赋值,找不到可以配对的值,c就是undifined。
适用场景:变量交换,选择性获取返回值
{
let a=1;
let b=2;
[a, b]=[b,a];
console.log(a, b);//2 1
}
{
function f() {
return [1,2];
}
let a,b;
[a, b]=f();//1 2
}
{
function f1() {
return [1,2,3,4,5];
}
let a,b,c;
[a, , ,b]=f1();
console.log(a, b);//1 4
}
{
function f1() {
return [1,2,3,4,5];
}
let a,b,c;
[a,...b]=f1();
console.log(a, b);//1 [2,3,4,5]
}
上面这两种也可以混合使用。
在用到数组成员对变量赋值时,尽量使用解构赋值。
对象的解构赋值::
{
let o={p:42,q:true};
let {p,q}=o;
console.log(p, q);//42 true
}
{
let {a=10,b=5}={a:3};
console.log(a, b);//3 5 a=10是默认值,找不到匹配项时才=10
}
使用场景:
{
let metaData={
title: 'abc',
test: [{
title: 'test',
desc: 'description'
}]
};
let {title:esTitle,test:[{title:cnTitle}]} = metaData;
console.log(esTitle,cnTitle);//abc test
}
函数的参数如果是对象的成员,优先使用解构赋值。
如果函数返回多个值,优先使用对象的解构赋值,而不是数组的解构赋值。这样便于以后添加返回值,以及更改返回值的顺序。
三、正则扩展
正则新增特性:u修饰符、y修饰符、s修饰符
{
//es5
let regex=new RegExp('xyz','i');
let regex2=new RegExp(/xyz/i);//或者直接/xyz/i
console.log(regex.test('xyz123'));//true
console.log(regex2.test('xyz123'));//true
//es6,参数可以下面这样
let regex3=new RegExp(/xyz/ig,'i');
console.log(regex3.flags);//i 即第二个参数的修饰符会覆盖前面正则表达式的修饰符
}
{
//y修饰符 vs g修饰符
let s='bbb_bb_b';
let a1=/b+/g;
let a2=/b+/y;
console.log('one',a1.exec(s),a2.exec(s));//bbb bbb
console.log('two',a1.exec(s),a2.exec(s));//bb null
//相同点:都是全局匹配
//不同点:g是上一次匹配的下一个字符开始,即_,不强调在第一个字符就能匹配上
//不同点:y是上一次匹配的下一个字符开始,即_,但是必须得在第一个字符就能匹配上
console.log(a1.sticky,a2.sticky);//false true 是否开启y
}
{
//u修饰符:unicode
console.log('u-1',/^\uDB3D/.test('\uDB3D\uDC2A'));//u-1 true //\uDB3D\uDC2A当成两个字符
console.log('u-2',/^\uDB3D/u.test('\uDB3D\uDC2A'));//u-2 false //\uDB3D\uDC2A当成一个字符
console.log(/\u{61}/.test('a'));//false
console.log(/\u{61}/u.test('a'));//true
console.log(`\u{20BB7}`);//unicode编码大于FFFF,即大于两个字节
let s='𠮷';
console.log(/^.$/.test(s));//false
console.log(/^.$/u.test(s));//true
console.log('test',/𠮷{2}/.test('𠮷𠮷'));//test false
console.log('test2',/𠮷{2}/u.test('𠮷𠮷'));//test2 true
//总结,大于两个字节长度的字符,要加u
//但是仍然不能匹配换行符,回车符,行分隔符,段分隔符
//如果要能匹配,使用s修饰符,但是s修饰符es6尚未实现
}
四、字符串扩展
安装补丁库,处理兼容:npm install babel-polyfill --save-dev
需要引入兼容库:
import 'babel-polyfill';
{
console.log('a','\u0061');//a a
console.log('a','\u20BB7');//a ₻7 超过了0xFFF,即两个字节,会被当成两个字符
console.log('s',`\u{20BB7}`);//s 𠮷
}
{
let s='𠮷';
//es5
console.log('length',s.length);//2 (码字大于两个字节,当四个字节处理,计算长度的时候每两个字节算一个长度)
console.log('0',s.charAt(0));//0 乱码
console.log('0',s.charAt(2));//0 乱码
console.log('at0',s.charCodeAt(0));//at0 55362
console.log('at1',s.charCodeAt(1));//at0 57271
//es6
let s1='𠮷a';
console.log('length',s1.length);//3
console.log('code0',s1.codePointAt(0));//134071 取出4个字节
console.log('code0',s1.codePointAt(0).toString(16));//20bb7
console.log('code1',s1.codePointAt(1));//57271 取出后两个字节
console.log('code1',s1.codePointAt(2));//97 就是a
//.toString(16)转成16进制
}
{
//es5
console.log(String.fromCharCode('0x20BB7'));//乱码
//es6
console.log(String.fromCodePoint('0x20BB7'));//𠮷
}
{
let str='\u{20BB7}abc';
for (let i=0;i<str.length;i++){
console.log('es5',str[i]);//前两个乱码 a b c
}
for (let code of str){
console.log('es6',code);//𠮷 a b c
}
}
{
let str='string';
console.log('includes',str.includes('r'));//true
console.log('start',str.startsWith('str'));//true
console.log('end',str.endsWith('ng'));//true
}
{
let str='abc';
//es5是用+
console.log(str.repeat(2));//abcabc
}
//模板字符串
{
let name='list';
let info='hello world';
let m=`i am ${name},${info}`;
console.log(m);//i am list,hello world
console.log('1'.padStart(2,'0'));//01
console.log('1'.padEnd(2,'0'));//10
}
//标签模板:放置XSS攻击,处理多语言
{
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);//["i am ", ",", "",] "list" "hello world"
return s+v1+v2;//i am ,,,listhello world
}
}
{
console.log(String.raw`Hi\n${1-2}`);//Hi \n-1
console.log('Hi\n${1+2}');//Hi 换行 ${1+2}
}
五、数值扩展
{
console.log(0b11110111);//247 0b二进制(大小写均可)
console.log(0o11111);//4681 0o八进制(大小写均可)
}
{
console.log('15',Number.isFinite(15));//true
console.log('NaN',Number.isFinite(NaN));//false
console.log('1/0',Number.isFinite(1/0));//false
console.log('NaN',Number.isNaN(NaN));//true
console.log('0',Number.isNaN(0));//false
console.log('25',Number.isInteger(25));//true
console.log('25.0',Number.isInteger(25.0));//true 25.0=25
console.log('25.1',Number.isInteger(25.1));//false
console.log('25.0',Number.isInteger('25.0'));//false
console.log(Number.MAX_SAFE_INTEGER);
console.log(Number.MIN_SAFE_INTEGER);
console.log(Number.isSafeInteger(10));//true 是否位于上面两个数的范围内
console.log(Number.isSafeInteger('a'));//false
//es5:Math.floor,Math.ceil
console.log(4.1,Math.trunc(4.1));//4
console.log(4.9,Math.trunc(4.9));//4
console.log('-5',Math.sign(-5));//-1
console.log('5',Math.sign(5));//1
console.log('0',Math.sign(0));//0
console.log('a',Math.sign('a'));//NaN
//开立方根
console.log(Math.cbrt(-1));//-1
console.log(Math.cbrt(8));//2
}
六、数组扩展
{
let arr=Array.of(3,4,7,9,11);
console.log('arr',arr);//[3,4,7,9,11]
console.log('arr',Array.of());//[]
}
{
let p=document.querySelectorAll('p');
let pArr=Array.from(p);//将上面的集合转义成数组
pArr.forEach(function (item) {
console.log(item.textContent);
});
//map
console.log(Array.from([1,3,5],function (item) {return item+2;}));//3 5 7
//填充数组
console.log('fill-7',[1,'a',undefined].fill(7));//[7,7,7]
console.log('fill,pos',['a','b','c','d','e'].fill(7,1,3));//["a", 7, 7, "d", "e"] 1和3表示起始和截至位置,不包括位置3
for (let index of ['1','c','ks'].keys()){
console.log('keys',index);//0 1 2
}
for (let value of ['1','c','ks'].values()){
console.log('values',value);//1 c ks
}
for (let [index,value] of ['1','c','ks'].entries()){
console.log(index,value);
}
console.log([1,2,3,4,5].copyWithin(0,3,4));//[4,2,3,4,5] (从0开始替换,从3开始读取,也就是第一个读取的数是4,4是截至位置,也就是在位置4之前,因此只取4)
console.log([1,2,3,4,5,6].find(function (item) {
return item>3;//4,只找第一个
}));
console.log([1,2,3,4,5,6].findIndex(function (item) {
return item>3;//3
}));
console.log('number',[1,2,NaN].includes(1));//true
console.log('number',[1,2,NaN].includes(NaN));//true
}
使用扩展运算符(...)拷贝数组:const itemsCopy = [...items];
七、函数扩展
{
function test(x, y='world') {
console.log('默认值',x, y);
}
test();//undefined world
let x='test';
function test2(x,y=x) {
console.log('作用域',x,y)
}
test2('kill');//kill kill
}
{//rest参数
function test3(...arg) {//将输入的参数都转为数组
for (let v of arg){
console.log('rest',v);//a b c
}
}
test3('a','b','c');
//将数组转成离散的值
console.log(...[1,2,4]);//1 2 4
console.log('a',...[1,2,4]);//a 1 2 4
}
{//箭头函数
let arrow = v => v+2;//v是参数,v+2是返回值
console.log('arrow',arrow(3));//5
//无参数情况下
let arrow2 = ()=> 2;
}
{//伪调用:函数的最后一句话是不是函数
function tail(x) {
console.log('tail',x);
}
function fx(x) {
return tail(x);
}
fx(123);//tail 123
}
八、对象扩展
这里的对象指Object对象
{
// 简洁表达法
let o=1;
let k=2;
let es5={
o:o,
k:k
};
let es6={
o,
k
};
console.log(es5,es6);//结果是一样的
let es5_mrthod={
hello:function () {
console.log('hello');
}
};
let es6_method={
hello(){
console.log('hello');
}
};
console.log(es5_mrthod,es6_method);//结果是一样的
//属性表达式
let a='b';
let es5_obj={
a: 'c'
};
let es6_obj={
[a]:'c' //这里的a是变量,即b
};
console.log(es5_obj,es6_obj);
//新增API
console.log('字符串',Object.is('abc','abc'));//true 相当于===
console.log('数组',Object.is([],[]),[]===[]);//false false 引用地址不同
//浅复制(只改引用地址)
console.log('拷贝',Object.assign({a:'a'},{b:'b'}));//{a: "a", b:"b"}
let test={k:123,o:456};
for (let [key,value] of Object.entries(test)){
console.log(key,value);
}
}
不要声明之后又给对象添加新属性,如果一定非要加请使用Object.assign。
九、Symbol用法
Symbol的概念:用symbol声明的变量,永远不相等。
{
//声明1
let a1=Symbol();
let a2=Symbol();
console.log(a1===a2);//false
//声明2
let a3=Symbol.for('a3');//'a3'会先检查a3是否在全局注册过,如果是,返回该值
let a4=Symbol.for('a3');
console.log(a3===a4);//true
//使用场景
let a5=Symbol.for('abc');
let obj={
[a5]: '123',
'abc': 345,
'c': 456
};
console.log(a5,obj);//Symbol(abc) {abc: 345,c: 456, Symbol(abc): "123"}
for (let [key,value] of Object.entries(obj)){
console.log('let of',key,value);
}
//let of abc 345
//let of c 456
Object.getOwnPropertySymbols(obj).forEach(function (item) {
console.log(obj[item]);//123
});
Reflect.ownKeys(obj).forEach(function (item) {
console.log(item,obj[item]);//可以将所有的key-value值打印出来
});
}
十、set-map数据结构
数据结构:set、weakset、map、weakmap
Object的key必须是字符串或者Symbol数据类型,而map的key可以是任意数据类型。
weakset与set支持的数据类型不同,weakset的元素只能是数据对象,且weakset中的对象是弱引用(地址引用),即不会检测这个对象是否在其他地方用过,也就意味着不会和垃圾回收机制挂钩(不会检测是否被回收)。
{//set
let list=new Set();//没有重复值
list.add(5);
list.add(7);
console.log('size',list.size);//2
let arr=[1,2,3,4,5];
let list1=new Set(arr);
console.log('size',list1.size);//5
let list2=new Set();
list2.add(1);
list2.add(2);
list2.add(1);
console.log('size',list2.size);//2
//重要应用场景:去重
let arr1=[1,2,3,1,2];
let list3=new Set(arr1);
console.log('unique',list3);//{1,2,3}
let arr2=[1,2,3,1,"2"];
let list4=new Set(arr2);
console.log('unique',list4);//{1,2,3,"2"}
let arr3=['add','delete','clear','has'];
let list5=new Set(arr3);
console.log(list5.has('add'));//true
console.log('delete',list5.delete('add'),list5);//true {"delete","clear","has"}
list5.clear();
console.log(list5);//set(0)
//key和value都是一样的
let list6=new Set(arr3);
for (let key of list6.keys()){
console.log('keys',key);
}
for (let value of list6.values()){
console.log('values',value)
}
for (let value of list6.values()){
console.log('values',value)
}
for (let [key,value] of list6.entries()){
console.log(key,value)
}
list6.forEach(function (item) {
console.log(item);
});
}
{//weakset
let weakList=new WeakSet();
let arg={};
weakList.add(arg);
//weakList.add(2);//报错
console.log(weakList);
//无clear方法,无size属性,不能遍历
}
{//map
let map=new Map();
let arr=['123'];
map.set(arr,459);
console.log(map,map.get(arr));
//第二种定义方式
let map1=new Map([['a',123],['b',456]]);
console.log(map1);//{"a"=>123,"b"=>456
console.log('size',map1.size);
console.log('delete',map.delete('a'),map);
console.log('clear',map.clear(),map);
//遍历同set
}
{//weakmap
let weakMap=new WeakMap();//接收对象必须是对象
//无size对象,无clear方法,不能遍历
}
十一、map-set与数组和对象的比较
{
//map与数组的对比
let map=new Map();
let array=[];
//增
map.set('a',123);
array.push({a:123});
console.info('map-array',map, array);
//查
let map_exists=map.has('a');//true
let array_exists=array.find(item =>item.a);//{a:123}
//改
map.set('a',2);
array.forEach(item => item.a?item.a=2:'');
//删
map.delete('a');
let index=array.findIndex(item=>item.a);
array.splice(index,1);
}
{
//set和array的对比
let set=new Set();
let array=[];
//增
set.add({t:1});
//查
let set_exist=set.has({t:1});
//改
set.forEach(item=>item.t?item.t=2:'');
//删
set.forEach(item=>item.t?set.delete(item):'');
}
{
//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.info({
map_exists: map.has('t'),
set_exists: set.has(item),
obj_exists: 't' in obj
});
//改
map.set('t',2);
item.t = 2;//set的改,引用类型
obj['t']=2;
//删
map.delete('t');
set.delete(item);
delete obj['t'];
}
如果只是简单的key: value结构,建议优先使用Map,因为Map提供方便的遍历机制。
十二、Proxy和Reflect
{
//proxy:代理
let obj={ //原始对象,存储真实数据
time: '2017-08-04',
name: 'net',
_r: 123
};
let monitor=new Proxy(obj,{//通过Proxy新生成一个对象
//拦截对象属性的读取
get(target,key){
return target[key].replace('2017','2018');
},
//拦截对象属性的设置
set(target,key,value){
if (key === 'name') {
return target[key]=value;
}else{
return target;//不做任何操作
}
},
//拦截key in Object 操作
has(target,key){
if (key === 'name'){
return target[key];
} else{
return false;
}
},
//拦截delete操作符
deleteProperty(target,key){
if (key.indexOf('_')>-1){
delete target[key];
return true;
}else{
return target[key];
}
},
//拦截Object.keys,Object.getOwnPropertySymbols,Object.getOwnPropertNames
ownKeys(target){
return Object.keys(target).filter(item=>item!='time');
}
});
//用户使用的是monitor
console.log(monitor.time);
monitor.time='2018';
console.log(monitor.time);//没有变化
monitor.name = 'com';
console.log(monitor.name);//com
console.log('name' in monitor);//true
delete monitor['time'];
console.log(monitor);//未删除
delete monitor._r;
console.log(monitor);//删除
console.log(Object.keys(monitor));//"name"
}
{
//reflect:方法同proxy
let obj={ //原始对象,存储真实数据
time: '2017-08-04',
name: 'net',
_r: 123
};
console.log(Reflect.get(obj,'time'));//2017-08-04
Reflect.set(obj,'name','com');
console.log(obj);//com
console.log(Reflect.has(obj,'name'));//true
}
{
//使用场景:数据类型的校验(与业务解耦的校验模块)
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);
}else{
throw Error(`不能设置${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);
}
}
const person=new Person('lilei',30);
console.info(person);//Proxy{name:"lilei",age:30}
person.name=48;//error:不能设置name为48
}
十三、类和对象
{
//类的基本定义和生成实例
class Parent{
//es6中定义构造函数
constructor(name='com'){
this.name=name;
}
}
let v_parent=new Parent('net');
console.info(v_parent);
//继承
class Child extends Parent{
}
console.log(new Child());//{name:"com"}
//继承传递参数,将参数传递给父类
class Child2 extends Parent{
constructor(name='child'){
super(name);//super一定放在构造函数的第一行
this.type='child';
}
}
console.log(new Child2());//{name:"child",type:"child"}
//getter,setter
class Parent2{
constructor(name='com'){
this.name=name;
}
get longName(){
return 'long'+this.name;
}
set longName(value){
this.name=value;
}
}
let v_parent2=new Parent2();
v_parent2.longName='net';
console.log(v_parent2.longName);//longnet
//静态方法、静态属性
class Parent3{
constructor(name='com'){
this.name=name;
}
static tell(){//静态方法
console.log('tell');
}
}
Parent.type = 'test';//这个就是静态属性
Parent3.tell();
}
十四、Promise
Promise是异步编程的一种解决方案。
{
//使用回调的方式
//缺点:如果是按顺序执行a,b,c...,代码的写法会非常复杂,代码的复杂影响后期的维护
let ajax=function (callback) {
console.log('执行');
setTimeout(function () {
callback&&callback.call();
},1000);
};
ajax(function () {
console.log('timeout1');
});
//使用promise解决方案
let ajax1=function () {
console.log('执行1');
return new Promise(function (resolve,reject) {
//resolve:要执行下一步的操作
//reject:要中断当前的操作
setTimeout(function () {
resolve();
},1000);
});
};
ajax1().then(function () {
console.log('promise','timeout2');
return new Promise(function (resolve,reject) {
setTimeout(function () {
resolve();
},1000);
});
})
.then(function () {
console.log('promise','timeout3');
});
}
{//捕获错误
let ajax=function (num) {
console.log('执行2');
return new Promise(function (resolve,reject) {
if (num>5){
resolve();
}else {
throw new Error('出错了');
}
});
};
ajax(2).then(function () {
console.log(6);
}).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 (img) {
document.body.appendChild(img);
});
}
Promise.all([
loadImg('http://i4.buimg.com/567571/df1ef0720bea6832.png'),
loadImg('http://i4.buimg.com/567571/2b07ee25b08930ba.png'),
loadImg('http://i4.buimg.com/567571/2b07ee25b08930ba.png')
]).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(img) {
let p=document.createElement('p');
p.appendChild(img);
document.body.appendChild(p);
}
Promise.race([
loadImg('http://i4.buimg.com/567571/df1ef0720bea6832.png'),
loadImg('http://i4.buimg.com/567571/2b07ee25b08930ba.png'),
loadImg('http://i4.buimg.com/567571/2b07ee25b08930ba.png')
]).then(showImgs);
}
十五、Iterator和for...of循环
{
let arr=['hello','world'];
let map=arr[Symbol.iterator]();
console.log(map.next());//{value:"hello",done:false}
console.log(map.next());//{value:"world",done:false}
console.log(map.next());//{value:undefined,done:false}
}
{
let obj={
start: [1,3,2],
end: [7,9,8],
[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);//1 3 2 7 9 8
}
}
{//for...of
let arr=['hello','world'];
for (let value of arr){
console.log(value);//hello world
}
}
十六、Genertor
Genertor也是异步编程的一种解决方案,但是相对promise更高级一点。
{
let state=function* (){
while(1){
yield 'A';
yield 'B';
yield 'C';
}
};
let status=state();
console.log(status.next());//A done:false
console.log(status.next());//B done:false
console.log(status.next());//C done:false
console.log(status.next());//A done:false
console.log(status.next());//B done:false
}
{//应用场景:抽奖
let draw=function (count) {
//具体抽奖逻辑略
console.info(`剩余${count}次`);
};
let residue=function* (count) {
while(count>0){
count--;
yield draw(count);
}
};
let start=residue(5);
let btn=document.createElement('button');
btn.id='start';
btn.textContent='抽奖';
document.body.appendChild(btn);
document.getElementById('start').addEventListener('click',function () {
start.next();
},false);
}
{//应用场景:定期向服务端获取数据,使用长轮询
let ajax=function* () {
yield new Promise(function (resolve,reject) {
setTimeout(function () {
resolve({code:0})
},200);
})
};
let pull=function () {
let generator=new ajax();
let step=generator.next();
step.value.then(function (d) {//step.value就是promise实例
if (d.code!=0) {//表示数据未更新
setTimeout(function () {
console.log('wait');
pull();
},1000);
}else{
console.log(d);
}
});
};
pull();
}
十七、Decorators
修饰器:一个函数,用来修改类的行为。
需要安装插件:npm install babel-plugin-transform-decorators-legacy --save-dev
.babelrc:"plugins":["transform-decorators-legacy"]
{
let readonly=function (target,name,descriptor) {
//target:修改类本身
//name:修改属性名称
//descriptor:属性的描述对象
descriptor.writable=false;
return descriptor;
};
class Test{
@readonly //修饰器
time(){
return '2017-03-11';
}
}
let test=new Test();
console.log(test.time());//2017-03-11
// test.time=function(){
// console.log('reset');//error: Cannot assign to read only property 'time' of object
// };
//在类外面操作必须在class前
let typename=function (target,name,descriptor) {
target.myname='hello';//静态属性
};
@typename
class Test2{
}
console.log(Test2.myname);//hello
//第三方库修饰器的js库:core-decorators(npm install core-decorators)
}
{//应用场景:埋点
//将埋点系统从业务逻辑中拆离
let log=(type)=>{
return function (target,name,descriptor) {
let src_method=descriptor.value;
descriptor.value=(...arg)=>{
src_method.apply(target,arg);
console.info(`log ${type}`);
}
}
};
class AD{
@log('show')
show(){
console.log('ad is show');
}
@log('type')
click(){
console.log('ad is click');
}
}
let ad=new AD();
ad.show();//ad is show log show
ad.click();//ad is click log type
}
十八、模块化
ES6的模块化语法:引入import、导出export
导出:
export let A=123;
export function test() {
console.log('test');
}
export class Hello {
test(){
console.log('class');
}
}
导入:
import {A,test,Hello} from "./class/lesson17";
console.log(A, test, Hello);
可以只导入部分变量:
import {A} from "./class/lesson17";
console.log(A);
起别名:
import * as lesson from "./class/lesson17";
console.log(lesson.A);
不给导出数据起名字(推荐):
let A=123;
function test() {
console.log('test');
}
class Hello {
test(){
console.log('class');
}
}
export default {
A,
test,
Hello
}
导入:
import lesson from "./class/lesson17";
console.log(lesson.A);