這篇文章將為大家詳細講解有關es7中修飾器Decorator怎么用,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

1. Decorator基本知識
在很多框架和庫中看到它的身影,尤其是React和Redux,還有mobx中,那什么是裝飾器呢。
修飾器(Decorator)是一個函數,用來修改類的行為。不是很理解這種抽象概念,還是看代碼講解實際些。
//定義一個函數,也就是定義一個Decorator,target參數就是傳進來的Class。
//這里是為類添加了一個靜態屬性
function addAge(target) {
target.age = 2;
}
//在Decorator后面跟著Class,Decorator是函數的話,怎么不是addAge(MyGeekjcProject)這樣寫呢?
//我只能這樣理解:因為語法就這樣,只要Decorator后面是Class,默認就已經把Class當成參數隱形傳進Decorator了(就是所謂的語法糖)。
@addAge
class MyGeekjcProject {}
console.log(MyGeekjcProject.age) // 2但上面這樣只傳了一個Class作為參數不夠靈活怎么辦?
我們可以在外層套一個函數,只要最后返回的是一個Decorator即可,管你套多少個函數傳多少個參數都無所謂。
function addAge(age) {
return function(target) {
target.age = age;
}
}
//注意這里,隱形傳入了Class,語法類似于addAge(2)(MyGeekjcProject)
@testable(2)
class MyGeekjcProject {}
MyGeekjcProject.age // 2
@addAge(3)
class MyGeekjcProject {}
MyGeekjcProject.age // 3下面是修改類的prototype對象
function description(target) {
target.prototype.url = 'https://www.geekjc.com';
}
@description
class MyGeekjcProject {}
let geekjc = new MyGeekjcProject();
geekjc.url // https://www.geekjc.com概念大概理解了,修飾器不僅可以修飾類,還可以修飾類的屬性
//假如修飾類的屬性則傳入三個參數,對應Object.defineProperty()里三個參數,具體不細說
//target為目標對象,對應為Class的實例
//name為所要修飾的屬性名,這里就是修飾器緊跟其后的name屬性
//descriptor為該屬性的描述對象
//這里的Decorator作用是使name屬性不可寫,并返回修改后的descriptor
function readonly(target, name, descriptor){
descriptor.writable = false;
return descriptor;
}
class Person {
@readonly
name() { return `${this.first} ${this.last}` }
}關于Object.defineProperty()可以看文章學習Object.defineProperty
再看一個復雜的例子
//定義一個Class并在其add上使用了修飾器
class Math {
@log
add(a, b) {
return a + b;
}
}
//定義一個修飾器
function log(target, name, descriptor) {
//這里是緩存舊的方法,也就是上面那個add()原始方法
var oldValue = descriptor.value;
//這里修改了方法,使其作用變成一個打印函數
//最后依舊返回舊的方法,真是巧妙
descriptor.value = function() {
console.log(`Calling "${name}" with`, arguments);
return oldValue.apply(null, arguments);
};
return descriptor;
}
const math = new Math();
math.add(2, 4);看完上面的代碼就知道decorator有什么用了,修飾器不僅可以修飾類的行為,還可以修飾類的屬性。
2. react高階組件
更通俗地描述為,高階組件通過包裹(wrapped)被傳入的React組件,經過一系列處理,最終返回一個相對增強(enhanced)的React組件,供其他組件調用。
3. 實現一個高階組件
面我們來實現一個最簡單的高階組件(函數),它接受一個React組件,包裹后然后返回。
export default function withDescription(WrappedComponent) {
return class HOC extends Component {
render() {
return <div>
<div className="geekjc-description">
極客教程(https://www.geekjc.com)致力于推廣各種編程語言技術,也為了未來數字化世界,讓人更容易找到操作數字化的方式,為了未來而生的編程學習平臺,
大部分資源是完全免費的,并且會根據當前互聯網的變化實時更新本站內容。
</div>
<WrappedComponent {...this.props}/>
</div>
}
}
}在其他組件里,我們引用這個高階組件,用來強化它。
@withDescription
export default class Geekjc extends Component {
render() {
return (
<div>
我是一個普通組件
</div>
);
}
}在這里使用了ES7里的decorator(可以看第一節的Decorator),來提升寫法上的優雅,但是實際上它只是一個語法糖,下面這種寫法也是可以的。
const EnhanceDemo = withDescription(Geekjc);
隨后,觀察React組件樹發生了什么變化,如圖所示,可以發現Geekjc組件被HOC組件包裹起來了,符合了高階組件的預期,即組件是層層包裹起來的,如同洋蔥一樣。

但是隨之帶來的問題是,如果這個高階組件被使用了多次,那么在調試的時候,將會看到一大堆HOC,所以這個時候需要做一點小優化,就是在高階組件包裹后,應當保留其原有名稱。
我們改寫一下上述的高階組件代碼,增加了getDisplayName函數以及靜態屬性displayName,此時再去觀察DOM Tree。
function getDisplayName(component) {
return component.displayName || component.name || 'Component';
}
export default function (WrappedComponent) {
return class HOC extends Component {
static displayName = `HOC(${getDisplayName(WrappedComponent)})`
render() {
return <div>
<div className="geekjc-description">
極客教程(https://www.geekjc.com)致力于推廣各種編程語言技術,也為了未來數字化世界,讓人更容易找到操作數字化的方式,為了未來而生的編程學習平臺,
大部分資源是完全免費的,并且會根據當前互聯網的變化實時更新本站內容。
</div>
<WrappedComponent {...this.props}/>
</div>
}
}
}
此時,原本組件的名稱正確地顯示在了DOM Tree上。
這個簡單的例子里高階組件只做了一件事,那便是為被包裹的組件添加一個標題樣式。這個高階組件可以用到任何一個需要添加此邏輯的組件上,只需要被此高階組件修飾即可。
由此可以看出,高階組件的主要功能是封裝并抽離組件的通用邏輯,讓此部分邏輯在組件間更好地被復用。
4. 高階組件的進階用法
4.1 組件參數
還是以上述例子為例,此高階組件僅僅只是展示了關于網站的描述,但是為了更好的抽象,此描述應當可以被參數化,如下方式調用。
@withDescription('歡迎大家訪問收藏(https://www.geekjc.com)')
export default class Geekjc extends Component {
render() {
return (
//...
);
}
}withDescription需要被改寫成如下形式,它接受一個參數,然后返回一個高階組件(函數)。
export default function (description) {
return function (WrappedComponent) {
return class HOC extends Component {
render() {
return <div>
<div className="geekjc-description">
{description
?description
: '我是描述'}
</div>
<WrappedComponent {...this.props}/>
</div>
}
}
}
}使用ES6寫法可以更加簡潔。
export default(description) => (WrappedComponent) => class HOC extends Component {
render() {
return <div>
<div className="geekjc-description">
{description
? description
: '我是描述'}
</div>
<WrappedComponent {...this.props}/>
</div>
}
}如圖可以看到,傳入的參數已經反映在DOM Tree里了。

柯里化 Curry
概念:只傳遞函數的一部分參數來調用它,讓它返回一個函數去處理剩下的參數。
函數簽名:fun(params)(otherParams)
應用:在React里,通過柯里化,我們可以通過傳入不同的參數來得到不同的高階組件。
屬性代理是最常見的高階組件的使用方式,上述描述的高階組件就是這種方式。它通過做一些操作,將被包裹組件的props和新生成的props一起傳遞給此組件,這稱之為屬性代理。
export default function withHeader(WrappedComponent) {
return class HOC extends Component {
render() {
const newProps = {
test:'hoc'
}
// 透傳props,并且傳遞新的newProps
return <p>
<WrappedComponent {...this.props} {...newProps}/>
</p>
}
}
}這種方式返回的React組件繼承了被傳入的組件,所以它能夠訪問到的區域、權限更多,相比屬性代理方式,它更像打入組織內部,對其進行修改。具體的可以參考附錄里提供的鏈接進行深入學習。
export default function (WrappedComponent) {
return class Inheritance extends WrappedComponent {
componentDidMount() {
// 可以方便地得到state,做一些更深入的修改。
console.log(this.state);
}
render() {
return super.render();
}
}
}上述高階組件為React組件增強了一個功能,如果需要同時增加多個功能需要怎么做?這種場景非常常見,例如我既需要增加一個組件標題,又需要在此組件未加載完成時顯示Loading。
@withDescription
@withLoading
class Demo extends Component{
}使用compose可以簡化上述過程,也能體現函數式編程的思想。
const enhance = compose(withHeader,withLoading);
@enhance
class Demo extends Component{
}組合 Compose
compose可以幫助我們組合任意個(包括0個)高階函數,例如compose(a,b,c)返回一個新的函數d,函數d依然接受一個函數作為入參,只不過在內部會依次調用c,b,a,從表現層對使用者保持透明。
基于這個特性,我們便可以非常便捷地為某個組件增強或減弱其特征,只需要去變更compose函數里的參數個數便可。
compose函數實現方式有很多種,這里推薦其中一個recompact.compose,詳情見下方參考類庫,也可以看我之前寫的一篇文章reduce與redux中compose函數
5. 與父組件區別
高階組件作為一個函數,它可以更加純粹地關注業務邏輯層面的代碼,比如數據處理,數據校驗,發送請求等,可以改善目前代碼里業務邏輯和UI邏輯混雜在一起的現狀。父組件則是UI層的東西,我們先前經常把一些業務邏輯處理放在父組件里,這樣會造成父組件混亂的情況。為了代碼進一步解耦,可以考慮使用高階組件這種模式。
6. 開源的高階組件使用
6.1 recompact
recompact提供了一系列使用的高階組件,可以增強組件的行為,可以利用此庫學習高階組件的寫法。
import recompact from 'recompact'
import { pure, withProps } from 'recompact'
const enhance = recompact.compose(
withProps({ className: 'beautiful' }),
pure,
)
@enhance
class Demo extends Component{
}通過使用此庫提供的高階組件,可以方便地讓列表元素可拖動。
關于“es7中修飾器Decorator怎么用”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
另外有需要云服務器可以了解下創新互聯scvps.cn,海內外云服務器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務器、裸金屬服務器、高防服務器、香港服務器、美國服務器、虛擬主機、免備案服務器”等云主機租用服務以及企業上云的綜合解決方案,具有“安全穩定、簡單易用、服務可用性高、性價比高”等特點與優勢,專為企業上云打造定制,能夠滿足用戶豐富、多元化的應用場景需求。
網站名稱:es7中修飾器Decorator怎么用-創新互聯
文章URL:http://www.yijiale78.com/article36/pcspg.html
成都網站建設公司_創新互聯,為您提供定制網站、網站導航、外貿網站建設、虛擬主機、手機網站建設、網站內鏈
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯