ホームページ > ウェブフロントエンド > jsチュートリアル > JavaScript デザイン パターンを学ぶ - デコレータ pattern_javascript スキル

JavaScript デザイン パターンを学ぶ - デコレータ pattern_javascript スキル

WBOY
リリース: 2016-05-16 15:19:19
オリジナル
1301 人が閲覧しました

クラスが本質的に大きくなり、一度に多くの責任が含まれることを望まない場合があります。次に、装飾されたパターンを使用できます。
デコレーター パターンは、このクラスから派生した他のオブジェクトに影響を与えることなく、オブジェクトに追加の役割を動的に追加できます。
装飾パターンは、あるオブジェクトを別のオブジェクトに埋め込みます。これは、実際には、このオブジェクトが別のオブジェクトによってラップされ、パッケージング チェーンを形成するのと同等です。

1. 元の関数を変更せずに関数にいくつかの追加関数を追加します

1. 元の見積を保存します

window.onload = function() {
  console.log(1);
};

var _onload = window.onload || function() {};

window.onload = function() {
  _onload();
  console.log(2);
}

ログイン後にコピー

質問:
(1) 中間変数は維持する必要があります
(2) これが乗っ取られる問題が発生する可能性があります
window.onload の例では、通常の関数 _onload を呼び出すときも window.onload を呼び出したときと同様に window を指すため、そのような問題はありません。

2. これはハイジャックされました:

var _getElementById = document.getElementById;
document.getElementById = function(id) {
  console.log(1);
  return _getElementById(id);
}

return _getElementById(id); // 报错“Uncaught TypeError: Illegal invocation”

ログイン後にコピー

_getElementById はグローバル関数であるため、グローバル関数が呼び出されるとき、this はウィンドウを指し、document.getElementById の this はドキュメントを指すことが期待されます。

3. ハイジャックされている問題を解決します:

var _getElementById = document.getElementById;
document.getElementById = function(id) {
  console.log(1);
  return _getElementById.call(document, id);
}
ログイン後にコピー

2. AOP を使用して関数を装飾します

/* 让新添加的函数在原函数之前执行(前置装饰)*/
Function.prototype.before = function(beforefn) {
  var _self = this;
  return function() {
    beforefn.apply(this, arguments);  // 新函数接收的参数会被原封不动的传入原函数
    return _self.apply(this, arguments);
  };
};

ログイン後にコピー
/* 让新添加的函数在原函数之后执行(后置装饰)*/
Function.prototype.after = function(afterfn) {
  var _self = this;
  return function() {
    var ret = _self.apply(this, arguments);
    afterfn.apply(this, arguments);
    return ret;
  };
};

ログイン後にコピー
document.getElementById = document.getElementById.before(function() {
  console.log(1);
});
ログイン後にコピー

3. プロトタイプの汚染を避ける

var before = function(fn, beforefn) {
  return function() {
    beforefn.apply(this, arguments);
    return fn.apply(this, arguments);
  };
};

var after = function(fn, afterfn) {
  return function() {
    var ret = fn.apply(this, arguments);
    afterfn.apply(this, arguments);
    return ret;
  };
};

document.getElementById = before(document.getElementById, function(){
  console.log(1);
});
ログイン後にコピー

4. 例 – プラグインフォームの検証

「JavaScript デザインパターンを学ぶ - 戦略パターン」 の [フォーム検証] と組み合わせて、ajax を適用してデータ検証を送信すると、効果は絶大です。

上記の前メソッドを変更します

var before = function(fn, beforefn) {
  return function() {
    if(beforefn.apply(this, arguments) === false) {
      // beforefn返回false,直接return,不执行后面的原函数
      return;
    }
    return fn.apply(this, arguments);
  };
};
ログイン後にコピー
/* 模拟数据验证*/
var validate = function() {
  if(username === "") {
    console.log("验证失败!");
    return false;
  }
  return true;
}
/* 模拟ajax提交*/
var formSubmit = function() {
  console.log("提交!!!");
}
ログイン後にコピー
username = 1;
formSubmit = before(formSubmit, validate); // 提交!!!
formSubmit();

username = "";
formSubmit = before(formSubmit, validate); // 验证失败!
formSubmit();
ログイン後にコピー

5. デコレータモードとプロキシモード

類似点: どちらのパターンも、オブジェクトにある程度の間接参照を提供する方法を記述しており、その実装部分は別のオブジェクトへの参照を保持し、そのオブジェクトにリクエストを送信します。
違い:
(1) プロキシ モード: 直接ローカル アクセスが不便な場合、または要件を満たさない場合、このオントロジーの代替手段を提供します。主要な機能をローカルで定義すると、エージェントはその機能へのアクセスを提供または拒否したり、オントロジーにアクセスする前に追加の処理を実行したりします。 (動作は本体と同じです)
(2) デコレータ モード: オブジェクトに動作を動的に追加します。 (最初からオブジェクトのすべての機能を決定したり、実際にオブジェクトに新しい責任や動作を追加したりすることはできません)

この記事が JavaScript プログラミングを学習するすべての人に役立つことを願っています。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート