ホームページ >ウェブフロントエンド >jsチュートリアル >es7のデコレータを詳しく解説(例付き)
この記事では、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
しかし、上記のメソッドが 1 つのクラスのみをパラメータとして渡し、十分な柔軟性がない場合はどうすればよいでしょうか。
最終結果が 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
以下は変更されたクラスのプロトタイプ オブジェクトです
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);上記のコードを読むと、デコレータが何に使用されるかがわかります。はい、修飾子はクラスの動作を変更するだけでなく、クラスの属性も変更できます。
2. React の高次コンポーネント
より一般的には、高次コンポーネントは、React コンポーネントをラップ (ラップ) することによって渡され、一連の最後に、他のコンポーネントを呼び出すために比較的強化された React コンポーネントが返されます。3. 上位コンポーネントを実装する
React コンポーネントを受け取り、それをラップして を返す、最も単純な上位コンポーネント (関数) を実装しましょう。export default function withDescription(WrappedComponent) { return class HOC extends Component { render() { return <div> <div> 极客教程(https://www.geekjc.com)致力于推广各种编程语言技术,也为了未来数字化世界,让人更容易找到操作数字化的方式,为了未来而生的编程学习平台, 大部分资源是完全免费的,并且会根据当前互联网的变化实时更新本站内容。 </div> <wrappedcomponent></wrappedcomponent> </div> } } }他のコンポーネントでは、この上位コンポーネントを参照して強化します。
@withDescription export default class Geekjc extends Component { render() { return ( <div> 我是一个普通组件 </div> ); } }ここでは、書き方の優雅さを向上させるために ES7 のデコレータを使用しています (最初のセクションのデコレータを参照) が、実際には単なる構文上の糖衣です。次のような書き方も可能です。
const EnhanceDemo = withDescription(Geekjc);次に、React コンポーネント ツリーでどのような変更が行われたかを観察します。図に示すように、Geekjc コンポーネントが HOC コンポーネントによってラップされていることがわかります。これは、高い期待と一致しています。 -order コンポーネント。つまり、コンポーネントはタマネギのようにレイヤーごとにラップされます。
しかし、それに伴う問題は、この上位コンポーネントが複数回使用されると、デバッグ時に次のように表示されることです。
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> 极客教程(https://www.geekjc.com)致力于推广各种编程语言技术,也为了未来数字化世界,让人更容易找到操作数字化的方式,为了未来而生的编程学习平台, 大部分资源是完全免费的,并且会根据当前互联网的变化实时更新本站内容。 </div> <wrappedcomponent></wrappedcomponent> </div> } } }
現時点では、元のコンポーネントの名前が DOM ツリーに正しく表示されます。 この単純な例では、上位コンポーネントはラップされたコンポーネントに
タイトル スタイル を追加するという 1 つのことだけを行います。この上位コンポーネントは、このロジックを追加する必要がある任意のコンポーネントで使用でき、この上位コンポーネントによってのみ変更する必要があります。
上位コンポーネントの主な機能は、コンポーネントの共通ロジックをカプセル化して抽象化し、ロジックのこの部分をコンポーネント間でより適切に再利用できるようにすることであることがわかります。4. 上位コンポーネントの高度な使用法
4.1 コンポーネントのパラメーター上記の例を例に挙げますが、この上位コンポーネントは情報のみを表示します。 Web サイトの説明についてですが、より適切に抽象化するには、この説明をパラメータ化して次のように呼び出す必要があります。
@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> {description ?description : '我是描述'} </div> <wrappedcomponent></wrappedcomponent> </div> } } } }ES6 を使用すると、より簡潔に記述できます。
export default(description) => (WrappedComponent) => class HOC extends Component { render() { return <div> <div> {description ? description : '我是描述'} </div> <wrappedcomponent></wrappedcomponent> </div> } }図からわかるように、渡されたパラメータが DOM ツリーに反映されています。 カリー化カリー
コンセプト: 関数のパラメータの一部だけを渡して呼び出し、残りのパラメータを処理する関数を返します。
関数シグネチャ: fun(params)(otherParams)
アプリケーション: React では、カリー化を通じて、さまざまなパラメーターを渡すことでさまざまな高次コンポーネントを取得できます。
export default function withHeader(WrappedComponent) { return class HOC extends Component { render() { const newProps = { test:'hoc' } // 透传props,并且传递新的newProps return <p> <wrappedcomponent></wrappedcomponent> </p> } } }4.3 逆継承に基づくこの方法で返された 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函数实现方式有很多种,这里推荐其中一个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のデコレータを詳しく解説(例付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。