裝飾器(Decorator)是一種與類(class)相關
的語法,用來註釋或修改類和類方法。 裝飾器是一種函數,寫成@ + 函數名
。它能夠放在類和類方法的定義前面。 其實只是一個語法糖. 尚未正式發佈, 還須要插件babel-plugin-transform-decorators-legacy
使用react
@testable
class MyTestableClass {
// ...
}
function testable(target) {
target.isTestable = true;
}
MyTestableClass.isTestable // true
複製代碼
上面代碼中,@testable
就是一個裝飾器。它修改了MyTestableClass
這個類的行爲,爲它加上了靜態屬性isTestable
。testable
函數的參數target
是MyTestableClass
類自己。es6
也就是說,裝飾器是一個對類進行處理的函數。裝飾器函數的第一個參數,就是所要裝飾的目標類。bash
function testable(target) {
// ...
}
複製代碼
若是想傳參,能夠在裝飾器外面再封裝一層函數。babel
function testable(isTestable) {
return function(target) {
target.isTestable = isTestable;
}
}
@testable(true)
class MyTestableClass {}
MyTestableClass.isTestable // true
@testable(false)
class MyClass {}
MyClass.isTestable // false
複製代碼
上面代碼中,裝飾器testable
能夠接受參數,這就等於能夠修改裝飾器的行爲。函數
注意,裝飾器對類的行爲的改變,是代碼編譯時發生的,而不是在運行時。這意味着,裝飾器能在編譯階段運行代碼。也就是說,裝飾器本質就是編譯時執行的函數。ui
前面的例子是爲類添加一個靜態屬性,若是想添加實例屬性,能夠經過目標類的prototype
對象操做。lua
function testable(target) {
target.prototype.isTestable = true;
}
@testable
class MyTestableClass {}
let obj = new MyTestableClass();
obj.isTestable // true
複製代碼
上面代碼中,裝飾器函數testable
是在目標類的prototype
對象上添加屬性,所以就能夠在實例上調用。spa
function testable(target) {
target.prototype.isTestable = true;
}
@testable
class MyTestableClass {}
let obj = new MyTestableClass();
obj.isTestable // true
複製代碼
經常須要寫成下面這樣prototype
class MyReactComponent extends React.Component {}
export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);
複製代碼
有了裝飾器,就能夠改寫上面的代碼。插件
@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {}
複製代碼
function readonly(target, name, descriptor){
// descriptor對象原來的值以下
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// };
descriptor.writable = false;
return descriptor;
}
readonly(Person.prototype, 'name', descriptor);
// 相似於
Object.defineProperty(Person.prototype, 'name', descriptor);
複製代碼
裝飾器第一個參數是類的原型對象,上例是Person.prototype
,裝飾器的本意是要「裝飾」類的實例,可是這個時候實例還沒生成,因此只能去裝飾原型(這不一樣於類的裝飾,那種狀況時target
參數指的是類自己);第二個參數是所要裝飾的屬性名,第三個參數是該屬性的描述對象。
其他使用方法與類的裝飾器相同(參數變爲3個了~)
若是同一個方法有多個裝飾器,會像剝洋蔥同樣,先從外到內進入,而後由內向外執行。
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
複製代碼
裝飾器只能用於類和類的方法,不能用於函數,由於存在函數提高。
import React from 'react';
export default Component => class extends React.Component {
render() {
return <div style={{cursor: 'pointer', display: 'inline-block'}}>
<Component/>
</div>
}
}
複製代碼
這個裝飾器(高階組件)接受一個 React 組件做爲參數,而後返回一個新的 React 組件。實現很簡單,就是包裹了一層 div,添加了一個 style,就這麼簡單。之後全部被它裝飾的組件都會具備這個特徵。 除了style還能夠傳參數
import React from 'react';
export default Component => class extends React.Component {
render() {
return <div test={'qwe'}>
<Component/>
</div>
}
}
複製代碼
之後全部被它裝飾的組件均可以從props
裏面獲取到test
. 他的值是'qwe'
。
發揮你的想象, 你能夠寫無數個很方便的高階組件, 經過裝飾器的方式, 讓你的代碼更簡潔, 更帥
索引