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); //橙 紅