let
/* let 声明变量 */
/* es6相对于es5的全局和局部作用域,多了一个块作用域,块作用域里声明的变量声明周期只在本块内 */
let a = 1;
console.info(a); // 输出1
for (let i=1;i<10;i++) {
console.info(i); // 在块内是可以正常使用的
}
console.info(i); // 异常,ReferenceError: i is not defined
// let是不能重复定义的
const
/* const 声明常量*/
/* const也是块作用域的 */
const PI = 3.14159265
const constObj = {
key1: 'value1',
key2: 'value2'
}
console.info(PI); // 输出3.14159265
console.info(constObj) // 输出Object { key1: "value1", key2: "value2" }
PI = 1 // 错误的,只读,不能修改
constObj = {key3: 'value3'} // 错误的,只读,不能修改
constObj.key1 = 1 // 可以修改,并不是因为常量可以修改,而是因为对象是引用类型的,这里只是修改对象的值,并没有修改对象的引用
console.info(constObj) // 输出Object { key1: 1, key2: "value2" }
解构赋值
/* 解构赋值 */
/* 左边一个结构,右边一个结构,左边与右边解开结构一一赋值 */
/* 变量交换、方法返回数组中存有多个变量、 只提取数组中的某些值、重组数组等场景*/
// 数组解构赋值
let a,b,c;
[a,b,c] = [1,2,3];
console.info(a); //输出1
console.info(b); //输出2
console.info(c); //输出3
[a,b,c =4] = [1,2];
console.info(a); //输出1
console.info(b); //输出2
console.info(c); //输出4,如果没有默认值,匹配不上,就是undefined
let d,e,f;
[d,e,...f] = [1,2,3,4,5,6,7,8,9,10];
console.info(d); //输出1
console.info(e); //输出2
console.info(f); //Array [ 3, 4, 5, 6, 7, 8, 9, 10 ]
// 对象解构
let obj1,obj2;
({obj1,obj2} = {obj1: 'val1', obj2: 'val2'});
console.log(obj1); //输出val1
console.log(obj2); //输出val2
字符串
- 字符串unicode扩展
/* 字符串unicode扩展 */
// \u表示后面是要输出一个unicoide编码对应的字符
let unicoideStr1 = '\u0061'
let unicoideStr2 = '\u20334'
//第一个正常输出是因为在二字节范围内的编码(0x0000-0xffff),第二个已经超过了两个字节的unicode编码表,会把前四位当成一个字符,最后一位当成一个字符
console.info(unicoideStr1,unicoideStr2) // a ″4
//显示两个字节以上的unicode编码,需要把编码用{}包起来
let unicoideStr3 = '\u{20334}'
console.info(unicoideStr1,unicoideStr3) // a ?
let spacStr = '?'
// es5中把超过两个字节长度编码的字符处理为4个字节,就是两个字符,输出2
console.info(spacStr.length) //输出2
let spacStrTest = '?a'
console.info(spacStrTest.length); //输出3
console.info("第一个字符",spacStr.charAt(0)) //输出 第一个字符 乱码
console.info("第二个字符",spacStr.charAt(1)) //输出 第一个字符 乱码
console.info("第二个字符编码",spacStr.charCodeAt(0)) //第一个字符编码 55360
console.info("第二个字符编码",spacStr.charCodeAt(1)) //第二个字符编码 57140
// 显然,这不是想要的结果,因此es5中处理这种字符是不正确的
console.info(spacStrTest.codePointAt(0)) //输出 131892
console.info(spacStrTest.codePointAt(0).toString(16)) //输出 20334
console.info(spacStrTest.codePointAt(1)) //输出 57140
console.info(spacStrTest.codePointAt(2)) //输出 97
//es5中根据编码取字符,大于两个字节的不能正常显示
console.info(String.fromCharCode('0x20334')) //输出乱码
//es6中根据编码取字符
// console.info(String.fromCodePoint('0x20334')) //输出 ?
//es5的循环不能正确取值
for(var i=0;i<spacStrTest.length;i++){
console.info(spacStrTest[i]); //输出两个乱码和一个a
}
//es6的循环可以正确取值
// for(let char of spacStrTest){
// console.info(char); //输出 ? a
// }
- 字符串其他扩展
/* 字符串其他扩展 */
let otherStrTest = 'string'
//是否包含
console.info(otherStrTest.includes('in')) //输出true
//是否起始
console.info(otherStrTest.startsWith('str')) //输出true
//是否结尾
console.info(otherStrTest.endsWith('ing')) //输出true
//复制10次
console.info(otherStrTest.repeat(10)) //输出stringstringstringstringstringstringstringstringstringstring (一共10次)
//字符串模板
let name = 'thatway'
let age = '18'
let man = `name is ${name},age is ${age}`
console.info(man) //输出name is thatway,age is 18
//padStart、padEnd 接收两个参数,第一个参数是长度,不够就补白,第二个是补白用的字符
let simpleStr = '1'
let leftPaddingStr = simpleStr.padStart(2,'0')
let rightpaddingStr = simpleStr.padEnd(2,'0')
console.info(leftPaddingStr, rightpaddingStr) //输出01 10
// raw会ie所有字符转义,就是在特殊字符钱加一个\,使其正常输出
console.info(String.raw('hello\nworld')) // 输出hello\nworld
console.info('hello\nworld')// 输出hello
//world
数组
/* 数组 */
// let arrTest1 = Array.of(1,2,3,4,5)
// console.info(arrTest1) //输出[1,2,3,4,5]
// let arr = [1,2,3,4,5]
// let arrTest2 = Array.from(arr)
// console.info(arrTest2) //输出[1,2,3,4,5]
// let arrTest3 = Array.from(arr,function(item){return item*2})
// console.info(arrTest3) //输出[2,3,6,8,10]
//fill,把数组中元素全部替换掉
let arrFill1 = [1,2,3]
console.info(arrFill1.fill(0)) //输出[0,0,0]
//fill,把数组中元素从第1个开始替换到第3个
let arrFill2 = [1,2,3,4,5]
console.info(arrFill2.fill(0,1,3)) //输出[ 1, 0, 0, 4, 5 ]
//遍历
// for(let [index,value] of ['1','2','3'].entries()){
// console.info(index,value)
// }
//find,查找元素,注意,只返回第一个符合的
let arrTest3 = [1,2,3,4,5]
console.info(arrTest3.find(function(item){return item > 3})) //输出4
console.info(arrTest3.findIndex(function(item){return item > 3})) //输出3
//是否包含某个值
let arrTest4 = [1,2,3,4,5,NaN]
console.info(arrTest4.includes(3)) // 输出true
console.info(arrTest4.includes(NaN)) // 输出true
函数
/* 函数 */
//参数默认值
function test1(x,y='123'){
console.info(x,y);
}
test1('abc') // 输出abc 123
test1('abc','def') // 输出abc def
//作用域
let x = 'abc'
function test2(x,y=x){
console.info(x,y)
}
test2('123') //输出123 123
test2() //输出 undefined undefined
function test3(z,y=x){
console.info(z,y)
}
test3('123') //输出123 abc
test3() //输出 123 undefined
//rest参数,参数不确定个数,如果生命了rest参数,不能再声明其他参数了
function test4(...params){
console.info(params)
}
test4(1,2,3,4,5) //Array [ 1, 2, 3, 4, 5 ]
test4(1) //Array [ 1 ]
test4() //[]
// ...数组 可以把数组里的值拆散成值
console.info(...[1,2,3,4,5]) //1 2 3 4 5
console.info('a',...[1,2,3,4,5])//a 1 2 3 4 5
//箭头函数
//es5的函数声明
function arrow5(){
console.info('arrow')
}
//es6的函数声明
//方法体只有一行的时候可以不写{}
let arrow6 = ()=>console.info('arrow')
arrow5() //arrow
arrow6() //arrow
let arrowTest = (x,y)=>{
console.info(x)
console.info(y)
}
arrowTest(1,2) //1 2
//--
//伪调用,优化嵌套、依赖函数,可提高性能
let fun1 = (x)=>{
console.info('fun1')
}
let fun2 = (x)=>{
return fun1(x)
}
console.info(fun2('abc'))
对象
/* 对象 */
let name= "thatway"
let age= 18
//es5的对象写法
let man5 = {
name:name,
age:age
}
//es6中可以将属性名与变量名相同的简写成一个
let man6 = {
name,
age
}
//结果是一样的
console.info(man5,man6);
//es5对象中的方法写法
let man5_method = {
play: function(){
console.info("玩")
}
}
//es6对象中的方法写法
let man6_method = {
play(){
console.info("玩")
}
}
//--
// let param = 'sex'
// //属性表达式
// let man5_obj = {
// name: 'thatway',
// age: 18
// }
//
// //es6属性名可以用变量
// let man6_obj = {
// name: 'thatway',
// age: 18,
// [param]: 'boy'
// }
// console.info(man5_obj,man6_obj)
// //比较两个对象是否是同一个,等同于===,注意引用类型的比较
// console.info(Object.is('abc','abc'))
Symbol
声明不想等的两个值,保证唯一性,babel不支持此API的编译,略过了,知道有这么回事先
Set
/* set */
let list1 = new Set()
list1.add("1");
list1.add("2");
console.info(list.size) //2
let arr = [1,2,3,4,5]
let list2 = new Set(arr)
console.info(list2.size) //5
let list3 = new Set()
list3.add(1)
list3.add(2)
list3.add(1)
//set中的值必须唯一,因此忽略第二个2,可以利用这个特性来去重
//去重的时候不会做类型的转换,比如1和'1'是可以同时存在的
console.info(list3.size) //2
//set有add、has、delete、clear几个方法
list3.has(1) //是否含有某个元素
list3.delete(1) //删除1 返回true代表成功
list3.clear() //清空
//遍历
for(let key of list3.keys()){
console.info(key)
}
for(let value of list3.values()){
console.info(value)
}
for(let [key,value] of list3.entries()){
console.info(key,value)
}
list3.forEach(function(item){
console.info(item)
})
//在webpack里为什么编译不通过呢,总觉得应该是配置的问题,有空查一下
//补充,这个问题是因为babel只转换es6的句法,不转换新的API...比如比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,解决这个问题的办法是引入babel-polyfill,它提供了es6语法的兼容。
$ npm install --save babel-polyfill
WeakSet
//WeakSet 和Set的区别是只能放对象,WeakSet是弱引用类型,可以防止内存泄露,其中的对象不存在引用时会被垃圾回收释放内存
//WeakSet 没有size属性 只有三个方法add、delete、has
let list_w = new WeakSet();
let obj = {
title : '111'
}
list_w.add(obj)
//异常,TypeError: [object WeakSet] is not iterable!
//WeakSet不支持遍历
// for(let item of list_w){
// console.info(item)
// }
//异常,TypeError: WeakSet value must be an object, got the number 1
list_w.add(1)
Map
//map
//map里放的是键值对,键可以是任何类型
let mapTest1 = new Map()
mapTest1.set("key","value")
console.info(mapTest1.get("key")) // 输出value
//用数组作为key
let arrKey = [1,2,3,4,5];
mapTest1.set(arrKey,"value2")
console.info(mapTest1.get(arrKey)) // 输出value2
// 用数组构造函数
let mapTest2 = new Map([['key1','abc'],['key2','def']]);
console.info(mapTest2.get('key1')) // abc
//map长度
console.info(mapTest2.size) //2
//其他方法
mapTest2.delete("key")
mapTest2.clear()
//遍历与set一样
WeakMap
WeakMap和WeakSet的特性一样,键必须是对象。
Proxy
/* proxy */
let objTest1 = {
name: 'thatway',
age: '18'
}
//代理objTest1,让用户去操作proxyTest,实际数据是存在于objTest1
//第一个参数是要代理的对象
//第二个参数是要拦截的各种配置
let proxyTest = new Proxy(objTest1,{
//拦截对象的读取
get(target,key){
return target[key]+"哦"
},
//拦截赋值操作
set(target,key,value){
return target['key']= value+"哦"
},
//拦截in操作,是否存在
has(target,key){
if(key == 'name'){
return false
}
},
//拦截delete
deleteProperty(target,key){
if(key == 'name'){
delete target[key]
return true
}else{
return target[key]
}
},
})
console.info(proxyTest.name) //thatway哦
proxyTest.name = "wp"
console.info(proxyTest) //name值被设置为wp哦
console.info(name in proxyTest); //false
console.info(delete proxyTest.name) //true
console.info(delete proxyTest.age) //true
console.info(proxyTest) //对象中没有了name,age还存在
proxy的操作
- get
get(target, propKey, receiver):拦截对象属性的读取,比如proxy.foo和proxy[‘foo’]。
- set
set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = v或proxy[‘foo’] = v,返回一个布尔值。
- has
has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。
- deleteProperty
deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。
- ownKeys
ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy),返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
- getOwnPropertyDescriptor
getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
- defineProperty
defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
- preventExtensions
preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。
- getPrototypeOf
getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象。
- isExtensible
isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。
- setPrototypeOf
setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
- apply
apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(…args)、proxy.call(object, …args)、proxy.apply(…)。
- construct
construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(…args)。
reflect
refect方法与proxy一一对应。
/* reflect */
//字母是反射的意思
//Reflect不用new
console.info(Reflect.get(objTest,'name')) //thatway
console.info(Reflect.set(objTest,'key','value'))
console.info(objTest)
reflect的设计目的,阮大神的文档中是这么说的:
1、 将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在Object和Reflect对象上部署,未来的新方法将只部署在Reflect对象上。也就是说,从Reflect对象上可以拿到语言内部的方法。
2、修改某些Object方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false。
3、让Object操作都变成函数行为。某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)让它们变成了函数行为。
4、Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。
Proxy与Reflex结合实例
//声明一个方法,返回值是一个代理对象,参数是实际对象和验证规则对象
//其目的是为了给原对象做一些列数据格式验证,用户在使用对象时拿到的实际上是代理对象,而不是实际对象
//这样的话就能够在用户填充数据时做一层拦截
let validator = (obj,validatorConfig)=> {
return new Proxy(obj,{
_validatorConfig:validatorConfig,
set(target,key,value,receiver){
if(target.hasOwnProperty(key)){
let validateAction = this._validatorConfig[key];
if(!!validateAction(value)){
return Reflect.set(target,key,value,receiver)
}else{
throw Error(`不能设置${key}到${value}`)
}
}else{
throw Error(`${key}不存在`)
}
}
});
}
//针对man对象的数据验证
const manValidator = {
name(val){
return typeof val === 'string'
},
age(val){
return typeof val === 'number' && val > 18
}
}
//创建对象
class Man{
constructor(name,age=18){
this.name= name
this.age= age
return validator(this,manValidator)
}
}
let manTest = new Man()
// manTest.name = 123 // Error: 不能设置name到123
manTest.name = 'thatway'
console.info(manTest) // 输出对象,其中name为thatway,age为18
// manTest.age = '20'// Error: 不能设置age到20
manTest.age = 20
console.info(manTest) // 输出对象,其中name为thatway,age为20
manTest.sex = 'boy' // Error: sex不存在
class
es6中定义类的关键字是class,不是Class
/* class */
//定义类
class Parent{
constructor(name='thatway'){
this.name= name
}
}
//实例化
let thatway = new Parent('wp');
console.log(thatway); //打印 Object { name: "wp" }
//继承类
class Child extends Parent{
}
let child1 = new Child()
console.info(child1) //Object { name: "thatway" }
let child2 = new Child('tutu')
console.info(child2) //Object { name: "tutu" }
class Tutu extends Parent{
constructor(name='child',type){
//子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象
super(name)
this.type = type
}
}
let tutu1 = new Tutu()
console.info(tutu1) //Object { name: "child", type: undefined }
let tutu2 = new Tutu('tutu','boy')
console.info(tutu2)//Object { name: "tutu", type: "boy" }
//getter、setter
class P{
constructor(name='thatway'){
this.name = name
}
set title(value){
this.name = value
}
get title(){
return this.name
}
}
let p = new P()
p.title = '123'
console.info(p.title)//123
console.info(p)//Object { name: "123" }
//静态方法
class S{
constructor(name='thatway'){
this.name = name
}
static sing(){
console.info('金色的河蓝色的海,都有我们快乐的身影...')
}
}
console.info(S.sing()) //金色的河蓝色的海,都有我们快乐的身影...
//静态属性,静态属性不使用static关键字,目前的方案是直接赋值
S.age = 18
console.info(S.age) //18
promise
// 使js异步操作更加合理强大
//es5中ajax回调模式
function ajax5(callback){
console.info("ajax5-1")
setTimeout(function(){
callback&&callback()
})
console.info("ajax5-2")
}
ajax5(function(){
console.info("callback5");
})
//es6 promise方式
let ajax6 = ()=> {
console.info("ajax6-1")
return new Promise((resolve,reject)=>{
console.info("ajax6-2")
setTimeout(()=>{
resolve()
},1000)
})
}
ajax6().then(()=>{
console.info("callback6")
})
let ajaxSencond = ()=>{
return new Promise((resolve,reject)=>{
return reject(new Error('second error'))
})
}
//promise实例的then方法返回一个新的promise实例,所以可以链式调用,这样就可以将多个异步操作变得有序
//第一个then返回的结果,会作为第二个then的参数
//then是有顺序的
ajax6().then(((data)=>{
console.info("ajax6 succ")
return "ajax6 rs"
}),(data)=>{
console.info("ajax6 error")
}).then((data)=>{
console.info("第二个then的resolve接收到的参数,可以拿着异步返回的结果做下面的逻辑了:"+data)
ajaxSencond().then((data)=>{
console.info("ajaxSencond succ")
},(data)=>{
console.info(data)
})
},(data)=>{
console.info("ajax6 error")
})
//异常的捕获,建议用catch
ajaxSencond().then((data)=>{
},(data)=>{
console.info("异常在这里出现-回调")
})
ajaxSencond().then((data)=>{
}).catch(function(data){
console.info("异常在这里出现-catch")
})
//all 所有的promise都返回结果以后才会then,如果其中一个失败了,则直接用失败的结果
let pro1 = new Promise((resolve,reject)=>{
return resolve("data1")
})
let pro2 = new Promise((resolve,reject)=>{
return resolve("data2")
})
Promise.all([pro1,pro2]).then(([data1,data2])=>{
console.info(data1,data2)
}).catch(function(error){
console.info(error)
}) //data1 data2
let pro3 = new Promise((resolve,reject)=>{
return reject(new Error('pro3 error'))
})
let pro4 = new Promise((resolve,reject)=>{
return resolve("data4")
})
Promise.all([pro3,pro4]).then(([data3,data4])=>{
console.info(data3,data4)
}).catch(function(error){
console.info(error)
}) //Error: pro3 error
//race 和all不一样的是,哪个先返回结果就用哪个的结果,其他的不用了
let pro5 = new Promise((resolve,reject)=>{
setTimeout(function(){
return resolve("data5")
},100)
})
let pro6 = new Promise((resolve,reject)=>{
return resolve("data6")
})
Promise.race([pro5,pro6]).then((data)=>{
console.log(data)
}).catch((data)=>{
console.log(data)
}) //data6
iterator
/* Iterator */
//数据集合结构的统一遍历方法
//具有Symbol.iterator属性的数据结构就可以使用for of循环遍历
function Obj(value) {
this.value = value;
this.next = null;
}
Obj.prototype[Symbol.iterator] = function() {
var iterator = { next: next };
var current = this;
function next() {
if (current) {
var value = current.value;
current = current.next;
return { done: false, value: value };
} else {
return { done: true };
}
}
return iterator;
}
var one = new Obj(1);
var two = new Obj(2);
var three = new Obj(3);
one.next = two;
two.next = three;
for (var i of one){
console.log(i); // 1, 2, 3
}
// 原生具备 Iterator 接口的数据结构如下。
//
// Array
// Map
// Set
// String
// TypedArray
// 函数的 arguments 对象
// NodeList 对象
Gernerator
/* Generator */
// generator是es6中的另一个异步解决方法
//基本定义
let tell = function* (){
yield 'a';
yield 'b';
return 'c'
}
let rs = tell()
console.info(rs.next()) //Object { value: "a", done: false }
console.info(rs.next()) //Object { value: "b", done: false }
console.info(rs.next()) //Object { value: "c", done: true } 有return的时候done会变为true
console.info(rs.next()) //Object { value: undefined, done: true }
//Generator返回的就是一个Iterator
let obj = {}
obj[Symbol.iterator] = function* (){
yield '1';
yield '2';
return
}
for(let val of obj){
console.info(val)
}
//Generator应用场景:状态机
//1、2、3三种状态
let state = function* (){
while (true){
yield 1;
yield 2;
yield 3;
}
}
let status = state();
for(let i = 0;i<= 10;i++){
console.info(status.next()) //一直是1、2、3依次输出
}
//抽奖次数限制
let action = (count)=> {
//抽一次奖品
console.info(`剩余${count}次`)
}
let timesController = function* (count){
while(count > 0){
count --
yield action(count)
}
}
let times = 5
let lottry = timesController(times)
lottry.next()
lottry.next()
lottry.next()
lottry.next()
lottry.next()
lottry.next()
//长轮询实例
let ajax = function* (){
//yield返回一个promise实例
yield new Promise((resolve,reject)=> {
//异步耗时1秒钟后返回结果
setTimeout(()=>{
return resolve('ok')
},1000)
})
}
//查询方法
let pull = ()=> {
//拿到Generator
let generator = ajax()
//执行ajax
let step = generator.next()
// step.value是返回的promise
step.value.then((data)=>{
//如果结果不是期望的,1秒以后再一次调用,直到结果是期望的
if(data != 'ok'){
setTimeout(()=>{
console.info("等待1秒后再轮询")
pull()
},1000)
}else{
console.info('结束了:'+data)
}
})
}
//开始拉取数据
pull()
Decorators
这个api需要插件支持
npm i babel-plugin-transform-decorators-legacy -D
.babelrc中添加插件
"plugins": ["transform-decorators-legacy"]
/* Decorator 修饰器 */
// 是一个函数
// 修改行为(可以修改或者扩展行为)
// 类的行为 (只能在类上使用)
// 类似于java的注解
//声明一个修饰器
let decoratorReadOnly = function(target,name,descriptor){
descriptor.writable = false
return descriptor
}
//修饰某一个类的行为
class Test{
@decoratorReadOnly
getName(){
return 'thatway'
}
}
let test = new Test()
test.getName = function(){
return 'new'
}//TypeError: "getName" is read-only
//也可以放在类前修饰类
let typeDecorator = function(target,name,descriptor){
target.name = 'a'
}
@typeDecorator
class Empty{}
console.info('修饰类',Empty.name) //"name" is read-only
//日志埋点
let log = (type)=> {
return function(target,name,descriptor){
let src_method = descriptor.value
descriptor.value =(...args)=>{
src_method.apply(target,args)
console.info(`log ${type}`)
}
}
}
class logTestObj {
@log('method1')
method1(){
console.info('method1')
}
@log('method2')
method2(){
console.info('method2')
}
}
let o = new logTestObj()
o.method1()
o.method2()
core-decorators包已经封装了常见的修饰符
npm i core-decorators
模块
模块主要涉及到import和export的语法,有几种不同情况下不同的写法。
学习资料
关于es6的入门,阮一峰大神已经整理的非常易懂了:
阮大神的babel介绍和ES6手册
http://www.ruanyifeng.com/blog/2016/01/babel.html
http://es6.ruanyifeng.com