フロントエンドエンジニアが知っておく必要のあるJavaScriptデザインパターン(詳細なマインドマップとソースコード付き)

序文

デザインモードは、プログラマーが進歩するために必要なスキルであり、エンジニアの作業経験と能力を判断するための試金石でもあります。デザインモードは、プログラマーの長年の作業経験を要約および要約したものであり、コードと既存のコードを大幅に最適化できます。合理的なリファクタリング:資格のあるフロントエンドエンジニアとして、デザインパターンを学習することは、自分の作業経験を要約して反映するもう1つの方法であり、高品質で保守性が高く、スケーラブルなコードを開発するための重要な手段でもあります。

jquery、react、vueなど、Golden Classicのいくつかの主要なフレームワークに精通しています。また、オブザーバーモード、プロキシモード、シングルトンモードなど、多数のデザインパターンがあるため、アーキテクトとして、デザインパターンを習得する必要があります。

ミドルおよびシニアフロントエンドエンジニアのインタビュープロセス中に、インタビュアーは求職者のデザインパターンの理解も適切に調査します。したがって、著者は長年の実務経験と学習の探求を組み合わせて、マインドマップとjavascriptデザインパターンを要約して描画します。実際のケースでは、次にXiを一緒に探索してみましょう。

あなたは得るでしょう

  • シングルトンモード

  • コンストラクターパターン

  • ビルダーモード

  • エージェンシーモデル

  • 外観モード

  • オブザーバーモード

  • 戦略モード

  • イテレーターモード

テキスト

まず概要を見てみましょう。デザインパターンは何をもたらすのでしょうか?


著者は、分離可能コードスケーラビリティ信頼性明快さ再利用など、プロジェクトがもたらすいくつかの設計パターンの主な利点を要約します。次に、最初のjavascriptを見ていきます。デザインパターン。

1.シングルトンモード

1.1概念の解釈

シングルトンモード:クラスにインスタンスが1つしかないことを確認するには、通常、最初にインスタンスが存在するかどうかを判断します。存在する場合は直接戻り、存在しない場合は作成してから戻ります。これにより、クラスにインスタンスオブジェクトが1つしかないことを確認できます。

1.2役割

  • モジュール間の通信

  • 特定のクラスのオブジェクトの一意性を保証します

  • 変動する汚染を防ぐ

1.3注意が必要な事項

  • これを正しく使用してください

  • 閉鎖はメモリリークを引き起こしやすいため、不要な変数を時間内にクリアする必要があります

  • 新しいオブジェクトを作成するコストは高くなります

1.4実際のケース

シングルトンモードは、さまざまなプログラミング言語で広く使用されており、コンピュータタスクマネージャ、リサイクルビン、Webサイトカウンタ、マルチスレッドスレッドプール設計などの実際のソフトウェアアプリケーションで広く使用されています。

1.5コードの実装


(function(){  // 养鱼游戏  let fish = null  function catchFish() {    // 如果鱼存在,则直接返回    if(fish) {      return fish    }else {      // 如果鱼不存在,则获取鱼再返回      fish = document.querySelector('#cat')      return {        fish,        water: function() {          let water = this.fish.getAttribute('weight')          this.fish.setAttribute('weight', ++water)        }      }    }  }
  // 每隔3小时喂一次水  setInterval(() => {    catchFish().water()  }, 3*60*60*1000)})()

2.コンストラクターモード

2.1概念の解釈

コンストラクターパターン:ビジネスロジックと関数の再利用性を実現するために、特定のタイプのオブジェクトを作成するために使用されます。

2.2機能

  • 特定のタイプのオブジェクトを作成する

  • ロジックとビジネスのカプセル化

2.3注意が必要な事項

  • ビジネスロジックの境界を分割することに注意してください

  • シングルトンと協力して、初期化やその他のタスクを実現します

  • コンストラクターの命名規則、最初の文字は大文字になります

  • プロトタイプチェーンにパブリックメソッドを配置する、新しいオブジェクトのコスト

2.4実際のケース

コンストラクターモードはコードの形式であり、プログラマーによるビジネスコードの理解度をテストするためにも使用されると思います。lodashなどのJavaScriptツールライブラリやJavaScriptフレームワークを実装するためによく使用されます。

2.5コード表示

function Tools(){
  if(!(this instanceof Tools)){
    return new Tools()
  }
  this.name = 'js工具库'
  // 获取dom的方法
  this.getEl = function(elem) {
    return document.querySelector(elem)
  }
  // 判断是否是数组
  this.isArray = function(arr) {
    return Array.isArray(arr)
  }
  // 其他通用方法...
}
3. 建造者模式

3.1概念の解釈

ビルダーモード:複雑なロジックまたは機能は、組織化された分業を通じて段階的に実現されます。

3.2機能

  • 配布して複雑なオブジェクトを作成するか、複雑な関数を実装します

  • 特定の作成の詳細に注意を払うことなく、カプセル化プロセスを切り離します

3.3注意が必要な事項

  • 信頼できるアルゴリズムとロジックでサポートされる必要があります

  • オンデマンドで特定のインターフェイスを公開する

3.4実際のケース

ビルダーモードは実際には多くの分野で適用されています。著者はこれまでに多くのjsプラグインを作成しており、そのほとんどがビルダーモードを採用しています。著者のgithubアドレスXu Xiaoxiのgithubを学習して参照できます。その他の場合は、次のとおりです。

  • Jqueryのajaxパッケージ

  • jqueryプラグインパッケージ

  • react / vueの特定のコンポーネントの設計

3.5コード表示

著者は、以前にビルダーモードを使用して実装されたケースを取り上げます。グラフィック検証コードのjavascriptオブジェクト指向の実装を使用した実際の戦闘へのキャンバスエントリ、非常に一般的な検証コードプラグインを実装するためにビルダーモードを使用しましょう!


// canvas绘制图形验证码(function(){    function Gcode(el, option) {        this.el = typeof el === 'string' ? document.querySelector(el) : el;        this.option = option;        this.init();    }    Gcode.prototype = {        constructor: Gcode,        init: function() {            if(this.el.getContext) {                isSupportCanvas = true;                var ctx = this.el.getContext('2d'),                // 设置画布宽高                cw = this.el.width = this.option.width || 200,                ch = this.el.height = this.option.height || 40,                textLen = this.option.textLen || 4,                lineNum = this.option.lineNum || 4;                var text = this.randomText(textLen);                    this.onClick(ctx, textLen, lineNum, cw, ch);                this.drawLine(ctx, lineNum, cw, ch);                this.drawText(ctx, text, ch);            }        },        onClick: function(ctx, textLen, lineNum, cw, ch) {            var _ = this;            this.el.addEventListener('click', function(){                text = _.randomText(textLen);                _.drawLine(ctx, lineNum, cw, ch);                _.drawText(ctx, text, ch);            }, false)        },        // 画干扰线        drawLine: function(ctx, lineNum, maxW, maxH) {            ctx.clearRect(0, 0, maxW, maxH);            for(var i=0; i < lineNum; i++) {                var dx1 = Math.random()* maxW,                    dy1 = Math.random()* maxH,                    dx2 = Math.random()* maxW,                    dy2 = Math.random()* maxH;                ctx.strokeStyle = 'rgb(' + 255*Math.random() + ',' + 255*Math.random() + ',' + 255*Math.random() + ')';                ctx.beginPath();                ctx.moveTo(dx1, dy1);                ctx.lineTo(dx2, dy2);                ctx.stroke();            }        },        // 画文字        drawText: function(ctx, text, maxH) {            var len = text.length;            for(var i=0; i < len; i++) {                var dx = 30 * Math.random() + 30* i,                    dy = Math.random()* 5 + maxH/2;                ctx.fillStyle = 'rgb(' + 255*Math.random() + ',' + 255*Math.random() + ',' + 255*Math.random() + ')';                ctx.font = '30px Helvetica';                ctx.textBaseline = 'middle';                ctx.fillText(text[i], dx, dy);            }        },        // 生成指定个数的随机文字        randomText: function(len) {            var source = ['a', 'b', 'c', 'd', 'e',            'f', 'g', 'h', 'i', 'j',             'k', 'l', 'm', 'o', 'p',            'q', 'r', 's', 't', 'u',            'v', 'w', 'x', 'y', 'z'];            var result = [];            var sourceLen = source.length;            for(var i=0; i< len; i++) {                var text = this.generateUniqueText(source, result, sourceLen);                result.push(text)            }            return result.join('')        },        // 生成唯一文字        generateUniqueText: function(source, hasList, limit) {            var text = source[Math.floor(Math.random()*limit)];            if(hasList.indexOf(text) > -1) {                return this.generateUniqueText(source, hasList, limit)            }else {                return text            }          }    }    new Gcode('#canvas_code', {        lineNum: 6    })})();// 调用new Gcode('#canvas_code', {  lineNum: 6})

4.エージェンシーモード

4.1概念の解釈

プロキシモード:オブジェクトは、特定のプロキシメソッドを介して別のオブジェクトへのアクセスを制御します。

4.2機能

  • リモートプロキシ(あるオブジェクトから別のオブジェクトへのローカルプロキシ)

  • 仮想プロキシ(大きなWebページのレンダリングなど、多くのオーバーヘッドを作成する必要があるオブジェクトの場合、実際の画像の代わりにサムネイルを使用できます)

  • セキュリティプロキシ(実際のオブジェクトへのアクセスを保護)

  • キャッシングプロキシ(一部の高価な操作は一時的なストレージを提供します。次の操作で、渡されたパラメーターが以前と同じである場合、以前に保存された操作の結果を直接返すことができます)

4.3注意が必要な事項

プロキシを使用するとコードが複雑になるため、プロキシを選択的に使用する必要があります。

実際のケース

プロキシモードを使用して、次の機能を実現できます。

  • キャッシングプロキシを介してコンピューティングパフォーマンスを最適化する

  • 画像プレースホルダー/スケルトン画面/プリロードなど

  • リクエスト/リソースのマージ

4.4コード表示

次に、計算バッファを実装してプロキシモードを適用する方法について説明します。


// 缓存代理function sum(a, b){  return a + b}let proxySum = (function(){  let cache = {}  return function(){      let args = Array.prototype.join.call(arguments, ',');      if(args in cache){          return cache[args];      }
      cache[args] = sum.apply(this, arguments)      return cache[args]  }})()

5.アピアランスモード

5.1概念の解釈

ファサード:サブシステム内の一連のインターフェイスに一貫したパフォーマンスを提供し、内部の複雑で面倒な詳細に注意を払うことなく、サブシステムを使いやすくします。

5.2機能

  • インターフェイスと発信者の特定のデカップリング

  • 古典的な3層構造のMVCを作成する

  • 開発フェーズでの異なるサブシステム間の依存関係と結合を減らして、各サブシステムの反復と拡張を容易にします

  • 大規模で複雑なシステムに明確なインターフェイスを提供する

5.3注意が必要な事項

開発者がアピアランスモードを継続的に呼び出すと、一定のパフォーマンス低下が発生します。これは、呼び出しが呼び出されるたびに可用性チェックが行われるためです。

5.4実際のケース

アピアランスモードを使用して、さまざまなブラウザや他のメソッドと互換性のあるイベントバインディングメソッド、またはインターフェイスを均一に実装する必要がある抽象クラスを設計できます。

5.5コード表示

次に、さまざまなブラウザと互換性のあるイベントリスニング機能を実装して、アピアランスモードの使い方をみんなに理解してもらいます。

function on(type, fn){
  // 对于支持dom2级事件处理程序
  if(document.addEventListener){
      dom.addEventListener(type,fn,false);
  }else if(dom.attachEvent){
  // 对于IE9一下的ie浏览器
      dom.attachEvent('on'+type,fn);
  }else {
      dom['on'+ type] = fn;
  }
}
6. 观察者模式

6.1概念の解釈

オブザーバーモード:1対多の関係が定義されています。すべてのオブザーバーオブジェクトが同時にサブジェクトオブジェクトをリッスンします。サブジェクトオブジェクトの状態が変化すると、すべてのオブザーバーオブジェクトに通知され、自動的に更新されます。

6.2機能

  • ターゲットオブジェクトとオブザーバーの間には動的な関係があり、柔軟性が向上します

  • シンプルなブロードキャスト通信をサポートし、サブスクライブされたすべてのオブジェクトに自動的に通知します

  • ターゲットオブジェクトとオブザーバーの間の抽象的な結合関係を拡張して、個別に再利用できます

6.3注意が必要な事項

通常、オブザーバーモードを最初に監視してからトリガーする必要があります(特別な状況では、QQのオフラインモードなど、最初に公開してからサブスクライブすることもできます)。

6.4実際のケース

オブザーバーパターンは非常に古典的なデザインパターンであり、その主な用途は次のとおりです。

  • システムメッセージ通知

  • ウェブサイトのロギング

  • コンテンツサブスクリプション機能

  • javascriptイベントメカニズム

  • react / vueなどのオブザーバー

6.5コード表示

次に、ネイティブjavascriptを使用してオブザーバーモードを実装します。


class Subject {  constructor() {    this.subs = {}  }
  addSub(key, fn) {    const subArr = this.subs[key]    if (!subArr) {      this.subs[key] = []    }    this.subs[key].push(fn)  }
  trigger(key, message) {    const subArr = this.subs[key]    if (!subArr || subArr.length === 0) {      return false    }    for(let i = 0, len = subArr.length; i < len; i++) {      const fn = subArr[i]      fn(message)    }  }
  unSub(key, fn) {    const subArr = this.subs[key]    if (!subArr) {      return false    }    if (!fn) {      this.subs[key] = []    } else {      for (let i = 0, len = subArr.length; i < len; i++) {        const _fn = subArr[i]        if (_fn === fn) {          subArr.splice(i, 1)        }      }    }  }}
// 测试// 订阅let subA = new Subject()let A = (message) => {  console.log('订阅者收到信息: ' + message)}subA.addSub('A', A)
// 发布subA.trigger('A', '我是徐小夕')   // A收到信息: --> 我是徐小夕

7.戦略モード

7.1概念の解釈

戦略モード:戦略モードは、さまざまなアルゴリズムを合理的に分類およびカプセル化するため、アルゴリズムのユーザーに影響を与えることなく、さまざまなアルゴリズムを相互に置き換えることができます。

7.2機能

  • 異なる実現、同じ効果

  • 呼び出し方法は同じであり、使用コストと異なるアルゴリズム間の結合を削減します

  • ユニットテストを容易にするために、アルゴリズムモデルを個別に定義します

  • elseのように、冗長なコード判断をたくさん避けてください。

7.3実際のケース

  • よりエレガントなフォーム検証を実現

  • ゲームのロールスコアラー

  • チェスとカードゲームの勝ち負けのアルゴリズム

7.4コード表示

次に、さまざまなタイプに応じて合計アルゴリズムを実装するモードを実装して、誰もが戦略モードを理解できるようにします。


const obj = {  A: (num) => num * 4,  B: (num) => num * 6,  C: (num) => num * 8}
const getSum =function(type, num) {  return obj[type](num)}

8.イテレーターモード

8.1概念の解釈

イテレーターモード:集約オブジェクトの各要素に順次アクセスするメソッドを提供します。ユーザーはメソッドの内部表現を気にする必要はありません。

8.2機能

  • さまざまなコレクションをトラバースするための統一されたインターフェイスを提供します

  • 元のコレクションを保護しますが、内部要素への外部アクセスを提供します

8.3実際のケース

イテレーターパターンの最も一般的なケースは、forEach、map、reduceなどの配列トラバーサルメソッドです。

8.4コード表示

次に、カプセル化したトラバーサル関数を使用して、イテレーターパターンの使用法を誰もがよりよく理解できるようにします。このメソッドは、配列と文字列をトラバースできるだけでなく、オブジェクトもトラバースできます。_。forEach(collection、[iteratee = _。アイデンティティ))メソッドも戦略モードの典型的なアプリケーションです。


function _each(el, fn = (v, k, el) => {}) {  // 判断数据类型  function checkType(target){    return Object.prototype.toString.call(target).slice(8,-1)  }
  // 数组或者字符串  if(['Array', 'String'].indexOf(checkType(el)) > -1) {    for(let i=0, len = el.length; i< len; i++) {      fn(el[i], i, el)    }  }else if(checkType(el) === 'Object') {    for(let key in el) {      fn(el[key], key, el)    }  }}

やっと

あなたがこの記事の完全なマインドマップを知りたい場合は、より多くのH5ゲームWebPACKのノードがぶ飲みCSS3JavaScriptのnodeJSキャンバスのデータの可視化と他のフロントエンドの知識と実際の戦闘は、学び、一緒に議論するパブリックアカウント「興味深いフロントエンド」にご参加を歓迎します、フロントエンドの境界を共同で探索します。

ドア更新ログ

以下の公式アカウントをフォローして、フロントエンドの知識を深め、学習コミュニティに参加することを歓迎します。

Webpack返信して、webpack4.0で単一ページ/複数ページの足場マインドマップを取得します

lodash返信すると、lodashAPIの中国のマインドマップが自分で翻訳されます。

学習パスに返信して 、著者の長年の経験のフロントエンド学習パスのマインドマップを取得します

フロントエンドについて話す

Vue、React、applet、Node 

 

フロントエンド アルゴリズム|パフォーマンス|アーキテクチャ|セキュリティ

おすすめ

転載: blog.csdn.net/KlausLily/article/details/109554789