Decorator装饰器
针对属性 / 方法的装饰器
// decorator 外部可以包装一个函数,函数可以带参数
function Decorator (type) {
/**
* 这里是真正的decorator
* @description: 装饰的对象的描述对象
* @target:装饰的属性所述类的原型,不是实例后的类。如果装饰的是Animal的某个属性,这个target就是Animal.prototype
* @name 装饰的属性的key
*/
return function (target, name, desciptor) {
// 因为babel的缘故 通过value并不能获取值,以此可以获取实例化的时候此属性的默认值
let v = desciptor.initializer && desciptor.initializer.call(this)
// 返回一个新的描述对象,或者直接修改desciptor也可以
return {
enumerable: true, //可以遍历
configurable: true, //可以删除
get: function () {
return v
},
set: function (c) {
v = c
}
}
}
}
// 上面的不能和业界商用的Decorator混用
function Check (type) {
return function (target, name, desciptor) {
let v = desciptor.initializer && desciptor.initializer.call(this)
// 将属性名字以及需要的类型的对应关系记录到类的原型上
if (!target.constructor._checkers_) {
// 将这个隐藏属性定义成no enumerable,遍历的时候是取不到的
Object.defineProperty(target.constructor, '_checkers_', {
value: {},
enumerable: false,
writable: true,
configurable: true
})
}
target.constructor._checkers_[name] = {
type: type
}
return desciptor
}
}
// 装饰函数的第一个参数 target 是包装属性所属的类的原型(prototype)
// 也就是把对应关系挂载到了开发定义的子类上。
vue中使用Decorator
- ts开发一定对vue-property-decorator不会感到陌生,这个插件提供了许多装饰器
- 在methods里面的方法上面使用装饰器,这时候装饰器的target对应的是methods。
- 可以在生命周期钩子函数上面使用装饰器,这时候target对应的是整个组件对象。
import {log,confirmation} from "./test"
methods: {
@log()
name() {
console.log("获取数据");
},
@confirmation('此操作将永久删除文件,是否继续?')
deleteFile(data){
//删除文件操作
}
},
mounted () {
this.name()
}
test.js
import {MessageBox}from "element-ui"
export function confirmation(message){
return function(target,name,descriptor){
let oldValue = descriptor.value
descriptor.value = function(...args){
MessageBox.confirm(message,'提示').then(oldValue.bind(this,...args)).catch(()=>{})
}
return descriptor
}
}
export function log(){
/**
* @description:
* @param {*} target 对应methods
* @param {*} name 对应属性方法的名称
* @param {*} descriptor 对应属性方法的修饰符
* @return {*}
*/
return function(target,name,descriptor){
console.log(target,name,descriptor);
// 获取实例化的时候此属性的默认值
const fn = descriptor.value
/* 重写 */
descriptor.value = function(...rest){
console.log(`调用${name}方法打印的`);
fn.call(this,...rest)
}
}
}
Iterator 迭代器
- 目的是为不同的数据结构提供统一的数据访问机制 主要为for of 服务的 (当for of执行的时候,循环过程中会自动调用这个对象上的迭代器方法,依次执行迭代器对象的next方法,并把next返回结果赋值给for of的变量,从而得到具体的值)
- 迭代器对象,返回此对象的方法叫做迭代器方法 此对象有一个next方法 每次调用next方法都会返回一个结果值
- 这个结果值是一个object 包含两个属性value和done
- value表示具体的返回值 done是布尔类型的,表示集合是否遍历完成或者后续还有可用数据,没有可用返回true, 否则返回false
内部会维护一个指针 用来指向当前集合的位置 每调用一次next方法 指针都会向后移动一个位置(可以想象成数组的索引)
代码实现
getInterator(list){
var i = 0;
return {
next:function(){
var done = (i>=list.length);
var value = !done ? list[i++]:undefined
return {
done:done,
value:value
}
}
}
}
var it = this.getInterator(['a','b','c'])
console.log(it.next());// {done: false, value: 'a'}
console.log(it.next());//{done: false, value: 'b'}
console.log(it.next());//{done: false, value: 'c'}
console.log(it.next());//{done: true, value: undefined}
可迭代对象
- Symbol.Iterator是一个表达式 返回Symbol的Iterator属性, 这是一个预定好的类型为Symbol的特殊值
- ES6规定,只要在对象上部署了Iterator接口,具体实现为给对象添加Symbol.Iterator属性,此属性指向一个迭代器方法,这个迭代器会返回一个迭代器对象。
而部署了这个属性,并且实现迭代器方法 返回的对象就是迭代器对象,此时这个对象就是可迭代的 可以被for for遍历
实现一个可迭代对象
getIterator(){ let iteratorObj = { items:[100,200,300], [Symbol.iterator]: function(){ var self = this var i =0 return { next:function(){ var done = (i>=self.items.length) var value = !done?self.items[i++]:undefined return { done:done, value:value } } } } } for(var item of iteratorObj){ console.log(item); //100 200 300 } } //上面的对象就是可迭代对象,可以被for of遍历 this.getIterator()
for of 中断
如果for of 循环提前退出,则会自动调用return方法,需要注意的是return 方法必须有返回值,且返回值必须是一个object
var arr = [100, 200, 300] arr[Symbol.iterator] = function () { var self = this var i = 0 return { next: function () { var done = i >= self.length var value = !done ? self[i++] : undefined return { done: done, value: value } }, return (){ console.log('提前退出'); return { //必须返回一个对象 done:true } } } } for (var o of arr) { if(o == 200){ break; } console.log(o) // 100 提前退出 }
除了for of 会调用对象的Iterator, 结构赋值也会
var str = '123' let [a,b]=str console.log(a,b); // 1 2 let map = new Map() map.set('q','1') map.set('a','2') map.set('b','3') let [c,d] = map console.log(c,d); //['q', '1'] ['a', '2']
因为普通对象不是可迭代对象。
自定义的可迭代对象进行解构赋值
var interatorObj = { items: ['橙', '红', '白'], [Symbol.iterator]: function () { let i = 0 let self = this return { next: function () { let done = i >= self.items.length let value = !done ? self.items[i++] : undefined return { done: done, value: value } } } } } let [a,b] = interatorObj console.log(a,b); //橙 红