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);//3
(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);//21 // 八进制:(octal) let b = 0o652; console.log(b);//426 // 十六进制:(hexadecimal) let c = 0xabc; console.log(c);//2748
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);//9007199254740991 // number.min_safe_integer:最小安全整数 console.log(number.min_safe_integer);//-9007199254740991
6.2math新增的东西
// math新增的东西 // math.trunc():截取数字整数部分 console.log(math.trunc(4.6));//4 // math.sign():判断一个数是正数、负数、0 console.log(math.sign(-5));//-1 console.log(math.sign(5));//1 console.log(math.sign(0));//0 console.log(math.sign(-0));//-0 console.log(math.sign('abc'));//nan // math.cbrt():计算一个数的立方根 console.log(math.cbrt(27));//3 // ...等等
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;//64 } }); 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);//7
检测对象的某一项属性是否存在:
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的一些东西,感谢观看!
上一篇: Header解析
下一篇: C# Quartz结合控制台实现定时任务