JavaScriptでクラスを使用する

JavaScriptでクラスを作成する方法は、ハーバーを含むRunet全体で何度も議論されてきましたが、実際のクラスに近いクラスを作成するための少し異なるアプローチを見つけることにしました。 多くの記事で説明されている他の実装との重要な違いの1つは、アクセサー(セッター/ゲッター)を作成する機能です。 これは、最新のブラウザーだけでなく、第9バージョン以下の長寿命IEでも機能します。 以下でそれについて読んでください。



まず、必要な型のクラスを作成する方法を説明します。クラスには、通常のパブリックプロパティ、プライベートプロパティ、および静的プロパティを設定できます。



クラス作成



クラスを作成するには、クラス名を宣言してオブジェクトを割り当てます。

空のクラスを作成する例:

classes.Class( "EmptyClass", {} ); //    classes.EmptyClass alert( classes.EmptyClass ); //  [class EmptyClass]
      
      





既に理解しているように、クラスを作成するのにコードを書くための大きな費用は必要ありません。



プライベートプロパティを持つクラスを作成するには、2番目のパラメーターがオブジェクトではなく、クラスオブジェクトが返される関数であることを宣言するだけで十分です。



プライベートプロパティを持つクラスの例:

 classes.Class( "PrivatePropertyClass", function(){ //   / var privateProp = "tratata", twoPrivateProp = "lalala"; //     return { } }); //    var privateTest = new classes.PrivatePropertyClass(); //     alert( privateTest.privateProp ); //  undefined
      
      





クラスは、クラスのコンテキストだけでなく、他のクラスでも作成できます。



たとえば、これがどのように行われるかをいくつか示しますが、何にも制限されることなく、受け入れ可能な任意の方法を選択できます。



便利なコンテキストでクラスを作成する方法は次のとおりです。

 //      window classes.Class.call( window, "GlobalClass", {} ); //      var CurrentContextClass = classes.Class( {} ); //           //     classes c  ClassesContextClass var CurrentContextClass = classes.Class( "ClassesContextClass", {} );
      
      





これについて、そしてクラスの作成が実際に完了すると、他の方法は必要ないと思います。



クラスを操作する



ここで、クラスの操作方法を示します。それらの作業の原理は、たとえばPHPに存在するクラスと変わりません。 「これはできません!」あなたは、はい、もちろんできません。 ここには微妙な点がありますが、もちろん、OOPのインターフェース、抽象化、およびその他の本格的な魅力を作成する方法はありません。 しかし、既存の機能を使用すると、プログラマはクラスプログラミングの知識を安全に使用でき、クラスの動作は予測可能であり、コンテキストは前後に実行されませんが、生成されたクラスの同じインスタンスを持ちます。



はじめに、情報をブラウザウィンドウに表示する簡単なクラスを作成しましょう。

 classes.Class( "Debug", function() { //   var //       BODY   body = null, //           body   cache = []; return { //  ,        //  callback   ,     constructor: function( callback ) { //          var listener = window.addEventListener ? [ "addEventListener", "" ] : [ "attachEvent", "on" ]; //       , //      if ( document.readyState === "complete" ) { //      ,     //       BODY body = document.body; //        //     if ( callback && typeof callback === "function" ) { callback.call( this ); } //      return; } //        callback' var self = this; //   ,       window[ listener[ 0 ] ]( listener[ 1 ] + "load", function() { //     ,     //      BODY body = document.body; //        ,   . for( var i = 0; i < cache.length; i++ ) { body.appendChild( cache[ i ] ); cache[ i ] = null; } //   cache.length = 0; //        //     if ( callback && typeof callback === "function" ) { callback.call( self ); } // bubbling - : http://learn.javascript.ru/bubbling-and-capturing }, false ); }, //             write: function() { //  DIV      var div = document.createElement( "DIV" ), //       ,   //       TRUE  //          DOM // . isPlainText = arguments.length ? arguments[ arguments.length - 1 ] === true : false, //      dataArray = Array.prototype.slice.call( arguments ); //       HTML   DOM  if ( isPlainText && dataArray.pop() ) { //       ,   //            DOM div.appendChild( document.createTextNode( dataArray.join( ", " ) ) ); } else { //        DOM . div.innerHTML = dataArray.join( ", " ); } //           if ( body ) { //        BODY  body.appendChild( div ); } else { //          BODY cache[ cache.length ] = div; } } } });
      
      





ここでは、本格的なクラスを作成しました。プライベートプロパティを使用するアプローチを使用しました。このクラスはそれほど複雑なことはしません。ブラウザウィンドウにテキストを表示するだけで、ドキュメントが完全に読み込まれるのを待っています。



たとえば、このクラスのインスタンスを作成して、最初のメッセージを出力できます。

 var debug = new classes.Debug(); debug.write( "  <var>classes.Debug</var>  !" );
      
      





「特別なことは何もありません!」あなたは言う、通常の不必要なクラスの作成は異なる方法で。 はい、私はあなたに答えます、ここには何も難解なものはありませんが、ほとんどのグッズはまだ言われていません。



継承



デバッグクラスのプロパティを継承する2番目のクラスを作成しましょう。 新しいクラスは、クリックすると色が変わる通常のボタンになります。

 //   ButtonClass      Debug classes.Class( "ButtonClass extends Debug", function() { //   var mouseState = 0, //   ,  DOM  button = null; //   function switchState( type ) { //     if ( type === 1 ) { mouseState++; //             button.style.backgroundColor = "green"; return; } else if ( type === 2 ) { mouseState--; } else { mouseState = 0; } //     button.style.backgroundColor = "red"; } return { //     constructor: function() { //     button = document.createElement( "SPAN" ); //      button.style.border = "1px solid blue"; button.style.color = "white"; button.style.textAlign = "center"; button.style.backgroundColor = "red"; button.style.borderRadius = "5px"; button.style.padding = "4px"; button.style.cursor = "default"; //      button.innerHTML = "  "; //    -   Debug //            //  ,   Debug      this.parent.constructor( function() { //      var self = this; //      DOM document.body.appendChild( button ); //     IE      button.onselectstart = function() { return false; } //     button.onmousedown = function( e ) { //     var e = e || window.event; //   ,    switchState( 1 ); //        //     . if ( e.preventDefault ) { e.preventDefault(); } else { e.returnValue = false; } } //      button.onmouseup = function() { //   , -  switchState( 2 ); //         if ( mouseState === 0 ) { //      //     self.click(); } } //       button.onmouseout = function() { //     ,    if ( mouseState && mouseState++ ) { //       switchState( 2 ); } } //        button.onmouseover = function() { //     ,   if ( mouseState && mouseState-- ) { //      switchState( 1 ); } } //          var handler = window.document.onmouseup; window.document.onmouseup = function( e ) { //        switchState(); //       if ( handler ) { handler.call( window, e ); } } }); }, //     DOM    node: function() { return button; }, //    ,       //          . click: function() { } } });
      
      





そして、既にお気づきのとおり、Debugクラスのプロパティを継承する新しいButtonClassクラスを作成しました。継承は、extendsの後にプロパティを継承するクラスの名前を追加することで行われます。



これは継承する唯一の方法ではなく、別の方法で実行することもできます。例:

 var Child = classes.Class( classes.Debug, {} );
      
      







ご覧のとおり、Childクラスはクラスの継承になりました。Debugクラス



では、書かれたボタンを試してみましょう

 //    var button = new classes.ButtonClass(); //        button.click = function() { //  write     Debug this.write( "         " ); } //         :) button.write( "  <var>classes.ButtonClass</var>  !" );
      
      





ご覧のとおり、完全に機能するボタンがありますが、美しくないかもしれませんが、これは些細なことです。 スタイル、ボタンの名前はいつでも変更できます。 これは、教室でプロジェクトを実装する方法のほんの一例です。



セッター/ゲッター



そして、バージョン9以下のInternet Explorerではゲッター/セッターを正常に操作できないことがわかっているため、これはプロジェクト開発の大きなマイナス点です。 はい、もちろん、言語の可能性はこれから減少することはなく、プログラムを書く可能性も減少しません。 しかし、それでも私はそれらを現在のクラスに実装しようとしました。むしろ、「マジックゲッター/セッター」と呼ぶことができます。ここでは、各プロパティのdefinePropertyをハングアップする必要はなく、どのプロパティをインターセプトできるかを指定するだけです。



ボタンクラスを拡張し、ゲッター/セッターを介してボタンテキストを変更できるようにするスーパークラスを作成します。 このクラスでは、コンストラクターまたはプライベートメソッドを使用せず、マジックゲッター/セッターによってインターセプトされるプロパティのみを作成します

 classes.Class( "SuperButtonClass extends ButtonClass", { //        / //  ,         //             //              $text: null, //  ,         //    property     ,   //       ,      //    set__: function( property, value ) { //             this.write( " SETTER   <var>" + property + "</var>   <var>" + value + "</var>" ); //    text if ( property === "text" ) { //        this.node().innerHTML = value; } }, //  ,           //  ,             // ,     . get__: function( property ) { //             this.write( " GETTER   <var>" + property + "</var>" ); //    text if ( property === "text" ) { //      return this.node().innerHTML; } } });
      
      





ここで、ボタンのスーパークラスを作成しました。これにより、必要な値であるtextプロパティへの通常の割り当てでボタンテキストを変更できるようになります。これはもちろん、すべてのゲッター/セッターオプションではなく、あらゆる条件、あらゆるタイプのデータなどで使用できます。



次に、取得したものを見てみましょう。

 //      var superButton = new classes.SuperButtonClass(); //  ,       //        superButton.write( "    : <var>" + superButton.text + "</var>" ); //              //         superButton.text = "   "; //           superButton.write( "  <var>classes.SuperButtonClass</var>  !" );
      
      





このリンクでは、説明されているすべての例を実際に見ることができます。



静的プロパティ



静的プロパティを具体的に記述することは意味がありません。誰もが知っているように、それらは誰もが知っている通常の方法で追加されます。

 classes.SuperButtonClass.NEW_STATIC = " ";
      
      







結論として、親メソッドを参照する場合、コンテキストを明示的に指定する必要がないという事実に注意を喚起したいと思います。 this.parent.constructor()の通常の呼び出しによって、ボタンクラスからDebugクラスのコンストラクターを呼び出すことに気づいたと思います。デバッグクラスには、最後の子孫、つまりクラスイニシエーターのコンテキストが既にあります。 既知の呼び出し、適用などを通じて親メソッドを呼び出す必要はありません。 this.parent.parentMethod(args)を呼び出すだけです。 そして、親relativeは子孫のコンテキストで動作します。



もちろん、クラスの既存のインスタンスに追加のゲッター/セッターを作成しても、9番目のバージョン以下のIEのようなブラウザーでは動作しません。 したがって、ダイナミクスには小さな制限があり、子孫および/またはその子孫のクラスでゲッター/セッターを使用する場合と同様に、プロパティを動的に追加することはできません。 ただし、この制限は、9番目のバージョンより下のIE、および少なくとも1つのゲッター/セッターが存在する場合にのみ適用されます。



SuperButtonClassクラスまたはその子孫のインスタンス用に、まだ持っていない追加のプロパティを作成するとします。 しかし、将来的にはとにかくそれらを持つことになります。 セッター/ゲッターを持つオブジェクトはVBScriptを介して生成されるため、作成しようとすると、9番目のバージョンよりも下のIEでエラーが発生します。



ただし、このクラスとその子孫にはセッター/ゲッターを使用しないため、ButtonClassクラスのインスタンスに追加のプロパティを簡単に作成できます。



また、ネイティブinstanceofがこれらのクラスに正しく応答しないことも追加したいので、これらのケースでは、classs.instanceOfメソッドを追加して、インスタンス呼び出しで必要なクラスにインスタンスが属しているかどうかを確認します。

 alert( classes.instanceOf( superButton, classes.Debug ) ); //  TRUE
      
      







この記事のクラスについては以上です。将来、おそらくいくつかの追加が行われるでしょう。

変更およびもちろんバグ修正。 開発中にそれらは特定されませんでした。



素敵なクラスの建物を作って、幸運を祈り、あなたの注意と将来の批判に感謝します!



リンクでクラスを操作するためのライブラリをダウンロードできます: http : //code.spb-piksel.ru/?classes.latest.zip

また、Github( https://github.com/devote)にも投稿します。Githubでは、他のプロジェクトもダウンロードできます。



UPD: Ashotのコメントの1つが述べたように、JavaScriptでクラスを構築するための多くの既に開発されたライブラリがあります。 しかし、このライブラリーは、アクセサー(セッター/ゲッター)を作成する機能を備えているという点で、それらすべてとは異なります。 上記のライブラリのいずれにも同様の実装は見つかりませんでした。 アクセサーは、最新のブラウザーだけでなく、第9バージョン以下のIEでも機能します。 これは、実装をクラス作成の他の実装と区別したいものです。



All Articles