寫在前面蜕衡,因?yàn)閒unction存在變量提升囚灼,所以修飾器是只能修飾類呢蛤,而不能修飾函數(shù)
- 修飾器是一個(gè)函數(shù),用來(lái)修改類的行為或?qū)傩?/li>
function testable(target) {
target.isTestable = true;
//也可以修改類的原型特铝,
target.prototype.isTestable = true
}
@testable
class MyTestableClass {}
// 上面的這一句等同于 MyTestableClass = testable(MyTestableClass)
console.log(MyTestableClass.isTestable) // true
翻譯過(guò)來(lái)暑中,其實(shí)它是這樣的
@decorator
class A {}
// 等同于
class A {}
A = decorator(A) || A;
所以可以看出修飾器其實(shí)就是一些函數(shù),用來(lái)修改類的行為(原型鲫剿,靜態(tài)屬性...都可以)鳄逾,只不過(guò)這些行為可能有公共性,所以就寫一個(gè)方法去改變灵莲,然后取了一個(gè)裝逼的名字叫修飾器
- 既然修飾器是一個(gè)函數(shù)雕凹,那么參數(shù)肯定少不了
function testable(isTestable) {
return function(target) {
target.isTestable = isTestable;
}
}
@testable(true)
class MyTestableClass {}
MyTestableClass.isTestable // true
@testable(false)
class MyClass {}
MyClass.isTestable // false
有點(diǎn)繞啊... 慢慢來(lái)
testable(true)
//相當(dāng)于返回一個(gè)函數(shù),我們用個(gè)變量接收一下
let resultFunc = testable(true)
//就相當(dāng)于
let resultFunc = function(target){
target.isTestable = true
}
//現(xiàn)在繼續(xù)修飾
@resultFunc
class MyTestableClass{}
//等同于原來(lái)的
@testable(true)
class MyTestableClass{}
// 是不是OK了政冻,要是需要多個(gè)參數(shù)枚抵,那就再最外面的函數(shù)中多傳就行
再來(lái)看一個(gè)列子,鞏固一下
function mixins(...list) {
return function (target) {
// 其實(shí)直接在外面使用這一句話就好明场,非要裝逼搞個(gè)修飾器的概念汽摹,好吧...,我承認(rèn)是因?yàn)檎镜牧?chǎng)不同,我是使用者的立場(chǎng)苦锨,他們是規(guī)范的立場(chǎng)
Object.assign(target.prototype, ...list)
}
}
const Foo = {
foo() { console.log('foo') }
};
@mixins(Foo)
class MyClass {}
let obj = new MyClass();
obj.foo() // 'foo'
- 修飾類的屬性
class Person {
@readonly
name() { return `${this.first} ${this.last}` }
}
function readonly(target, name, descriptor){
// descriptor對(duì)象原來(lái)的值如下
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// };
descriptor.writable = false;
return descriptor;
}
readonly(Person.prototype, 'name', descriptor);
// 類似于
Object.defineProperty(Person.prototype, 'name', descriptor);
很難理解是嗎逼泣,通過(guò)控制臺(tái)輸出,我們發(fā)現(xiàn)target其實(shí)是當(dāng)前類(因?yàn)楝F(xiàn)在是在類里面使用)的原型舟舒,name就是下面的屬性名拉庶,descriptor就是這個(gè)屬性的描述,修飾器修改的其實(shí)就是這個(gè)描述秃励,不知道描述是什么..請(qǐng)自行查閱資料,再來(lái)看一個(gè)例子
class Math {
@log
add(a, b) {
return a + b;
}
}
function log(target, name, descriptor) {
var oldValue = descriptor.value;
// 打印出來(lái)發(fā)現(xiàn)氏仗,oldValue其實(shí)就是function add(){}
descriptor.value = function() {
console.log(`Calling "${name}" with`, arguments);
return oldValue.apply(null, arguments);
};
return descriptor;
}
const math = new Math();
// passed parameters should get logged now
math.add(2, 4);
- 若是同一個(gè)方法有多個(gè)修飾器,會(huì)從外向內(nèi)進(jìn)入夺鲜,然后由內(nèi)向外執(zhí)行(簡(jiǎn)單理解就是把內(nèi)部執(zhí)行的結(jié)果當(dāng)做參數(shù)傳向外面的)
function dec(id){
console.log('evaluated', id);
return (target, property, descriptor) => console.log('executed', id);
}
class Example {
@dec(1)
@dec(2)
method(){}
}
// evaluated 1
// evaluated 2
// executed 2
// executed 1
- babel的支持性皆尔,需要安裝babel-plugin-transform-decorators插件,然后配置.babelrc,
npm install babel-core babel-plugin-transform-decorators
// .babelrc
{
"plugins": ["transform-decorators"]
}
- 第三方模塊core-decorators.js
參看自阮一峰ECMAScript 6 入門