私の拡張とクラス継承スタイル

この投稿では、大量のJavaScriptアプリケーションに継承を実装する方法を説明します。



プロジェクトが多くの関連するクラスを必要とし、そうではないクラスを想定します。

各タイプの動作を別々のクラスで記述しようとすると、多くのクラスが存在する可能性があります。 そして、最終クラスには十数人の先祖がいる可能性があります。 この場合、プロトタイプを介した通常のJavaScriptの継承では不十分な場合があります。 たとえば、先祖クラスの同様のメソッドを呼び出すメソッドからの機会が必要でした。 そして、クラスのいくつかの静的プロパティとメソッドを作成して継承したいと考えました。 この機能は、クラスごとに次のf-ju拡張を呼び出すことで追加できます。



拡張機能



cSO = {}; //     . cSO.extend = function(child, parent, other) { if(parent) { var F = function() {}; F.prototype = parent.prototype; child.prototype = new F(); child.prototype.constructor = child; child.prototype.proto = function() { return parent.prototype; } //   . } else { child.prototype.proto = function() { return; } } /* *     stat,    -  . *    _class.stat   ()   this.stat. *       ,     *  : _class.stat.prototype.myStaticMethod = function() {...<anchor>habracut</anchor> *    ,    prototype. *    stat  ,     . *     stat -  _class.stat.deleteStatVal("name"); */ child.statConstructor = function() {}; if(parent && ("statConstructor" in parent) && parent.statConstructor && typeof (parent.statConstructor) === "function") { var S = function() {}; S.prototype = parent.statConstructor.prototype; child.statConstructor.prototype = new S(); child.statConstructor.prototype.constructor = child.statConstructor; child.statConstructor.prototype.proto = function() { return parent.statConstructor.prototype; } child.statConstructor.prototype.protoStat = function() { return parent.stat; } } else { child.statConstructor.prototype.proto = function() { return; } child.statConstructor.prototype.protoStat = function() { return; } } var oldChildStat = child.stat; //   stat -  ... child.stat = new child.statConstructor(); if(oldChildStat) { //       . for(var k in oldChildStat) { child.stat[k] = oldChildStat[k]; } } child.stat.prototype = child.statConstructor.prototype; if(oldChildStat && oldChildStat.prototype) { //         . for(var k in oldChildStat.prototype) { child.stat.prototype[k] = oldChildStat.prototype[k]; } } child.prototype.stat = child.stat; if(other) { //      . if(other.statConstruct) { child.stat.prototype.construct = other.statConstruct; } } child.stat._class = child; //       . child.stat.deleteStatVal = function(name) { //   ,      . if( name in child.stat) { try { delete child.stat[name]; } catch(e) { } if(parent) { child.stat[name] = child.stat.protoStat()[name]; } } } child.prototype.protoFunc = child.statConstructor.prototype.protoFunc = function(callerFuncName, args, applyFuncName) { /* *          (  *  - -     ).   *  applyFuncName -  callerFuncName    -   *     ,     -. */ if(!args) { args = []; } if(applyFuncName) { //    ,     . } else { applyFuncName = callerFuncName; } var tProto = this; var ok = false; do { if(ok && arguments.callee.caller !== tProto[applyFuncName]) { if(( applyFuncName in tProto) && ( typeof (tProto[applyFuncName]) === "function")) { return tProto[applyFuncName].apply(this, args); } } else if(arguments.callee.caller === tProto[callerFuncName]) { ok = true; } } while(("proto" in tProto) && (tProto = tProto.proto())) return; } if(child.stat.construct) { //         stat.construct child.stat.construct(); } }
      
      







それがどのように機能するかについての小さなチェック、および拡張の結果()



それぞれ3つのクラスを作成します。前のクラスの相続人です。



 cSO.class001 = function() { } cSO.extend(cSO.class001, 0, {"statConstruct":function(sc1) { console.log("statConstruct001"); }}); //  statConstruct001 cSO.class001.prototype.construct = function(c1) { console.log('c1'); this.protoFunc("construct", arguments); } cSO.class001.stat.prototype.st = function(s1) { console.log('st1'); this.protoFunc("st"); } cSO.class001.stat.dat = ["hello1"]; cSO.class002 = function() { } cSO.extend(cSO.class002, cSO.class001, {"statConstruct":function(sc2) { console.log("statConstruct002"); this.protoFunc("construct", arguments); }}); //  statConstruct002 statConstruct001 cSO.class002.prototype.construct = function(c2) { console.log('c2'); this.protoFunc("construct", arguments); } cSO.class002.stat.st = function(s2) { console.log('st2'); this.protoFunc("st"); } cSO.class003 = function() { } cSO.extend(cSO.class003, cSO.class002); //  statConstruct002 statConstruct001 cSO.class003.prototype.construct = function(c3) { console.log('c3'); this.protoFunc("construct", arguments); } cSO.class003.stat.prototype.st = function(s3) { console.log('st3'); this.protoFunc("st"); } cSO.class003.stat.dat = ["hello3"];
      
      







そして今、私たちは彼らの行動が実行される順番を見つけます。



 var obj001 = new cSO.class001(); var obj002 = new cSO.class002(); var obj003 = new cSO.class003(); obj001.construct(); // c1 obj002.construct(); // c2 c1 obj003.construct(); // c3 c2 c1 cSO.class001.stat.st(); // st1 cSO.class002.stat.st(); // st2 st1 cSO.class003.stat.st(); // st3 st1 //    cSO.class002.stat.st  prototype console.log(obj003.stat.dat); // ["hello3"] obj002.stat.dat = ["world"]; console.log(obj002.stat.dat); // ["world"] cSO.class002.stat.deleteStatVal("dat"); console.log(obj002.stat.dat); // ["hello1"] console.log(obj001.stat.dat); // ["hello1"]
      
      







私にとって重要だと思われたいくつかのタッチ



毎日の練習の結果、おおよそ次のオブジェクトの構造があります。

 _class={ construct:function(){}, //     -. destruct:function(){}, //     -. //  .. stat:{ create:function(){}, //       . collection:[], //        . clearAll:function(){} //       . //  .. } }
      
      





では、その理由を説明します。

クラスを作成するには、コンストラクターを呼び出す必要があります。コンストラクターは、このクラスの子オブジェクトを作成するときにnew Foo()が呼び出されないときに呼び出されます。



以下に例を示します。



 var id = 0; var Foo = function() { this.id = id++; console.log("  ,   boom"); } foo.prototype.boom = function() {} var Bar = function() { } Bar.prototype = new Foo(); var fooOb = new Foo(); //   ,   boom var barOb = new Bar(); var barOb2 = new Bar(); console.log(fooOb.id); // 1 console.log(barOb.id); // 0 console.log(barOb2.id); // 0
      
      







そして、Fooクラスの相続人であるすべてのオブジェクトに一意のIDを持たせ、爆発できることをユーザーに警告したいと思います。

これを実装するには、特別なcnstructメソッドを作成し(コンストラクターは既に使用されています)、各オブジェクトを作成するときに実行します。 実行することを忘れないために、新しいFoo()でオブジェクトを作成することを拒否し、静的メソッドFoo.stat.create()でオブジェクトを作成します。

以下は、クラスを取得する方法の例として、実際に使用されるクラスの短縮バージョンです。



実際の例



このクラスは、基本クラスから最終クラスまでのプロトタイプチェーン内の多くの1つ(ほとんどの場合、反対方向)と見なす必要があります。

 (function() { var _class = cSO.LocalStorageSyncDataType = function () { /* *     ,  *       . *     ,  . */ } cSO.extend(_class, cSO.ServerSyncDataType, {"statConstruct": function() { this.protoFunc("construct", arguments); //   ,      protoFunc -    . if("addToClassesForSnapshot" in this) { //     cSO.LocalStorageSyncDataType,    ,     . this.addToClassesForSnapshot(this._class); //      . } }}); var _class_stat = _class.stat; //   -   ()     15%-25%   .       . var _class_stat_prototype = _class_stat.prototype; var _class_prototype = _class.prototype; var cfs = _class_stat.classesForSnapshot = []; _class_stat.create = function(args) { //     ,   ..   . this.addedToLocalStorage = false; if(args.addedToLocalStorage) { this.addedToLocalStorage = true; } this.protoFunc("construct", arguments); } _class_prototype.construct = function(args) { /* *    ,    . *         . */ this.addedToLocalStorage = false; if(args.addedToLocalStorage) { this.addedToLocalStorage = true; } this.protoFunc("construct", arguments); } _class_prototype.setLoaded = function(val) { this.protoFunc("setLoaded", arguments); // ,    ,      . } _class_stat.addToClassesForSnapshot = function(clas) { clas = clas || this._class; for(var i = 0; i < cfs.length; i++) { if(cfs[i] === clas) return; } cfs.push(clas); } _class_stat.createAllSnapshots = function() { for(var i = 0; i < cfs.length; i++) { cfs[i].stat.createSnapshot(); } } _class_stat_prototype.createSnapshot = function() { var co = this.collection; var str = ""; for(var i in co) { if(co[i]) { if(!str) { str = "["; } else { str += ","; } str += co[i].getJSON(); } } if(str) str += "]"; this.snapshot = str; } _class_stat.saveAllSnapshotsOnLocalStorage = function() { for(var i = 0; i < cfs.length; i++) { cfs[i].stat.saveSnapshotOnLocalStorage(); } } _class_stat_prototype.saveSnapshotOnLocalStorage = function() { if(this.snapshot) { cSO.localStorage.setItem(this.tableName, this.snapshot); } } _class_stat.setAllBySnapshotsFromLocalStorage = function() { for(var i = 0; i < cfs.length; i++) { cfs[i].stat.setBySnapshotFromLocalStorage(); } } _class_stat_prototype.setBySnapshotFromLocalStorage = function() { var arr = $.parseJSON(cSO.localStorage.getItem(this.tableName)); for(var i = 0; i < arr.length; i++) { if(arr[i]) { this.createOrGet({"cells":arr[i], "addedToLocalStorage":true}); } } } })();
      
      







このアプローチは、特にオブジェクトクラスに使用する必要があり、「孤立した」オブジェクト(cSO.localStorageなど)には、従来のオブジェクトファクトリを使用する価値があると付け加えます。



PSこのアプローチでは、ほとんどのプログラミング概念と実行速度が大幅に低下することを理解しています。

また、そのようなスタイルは新しいものではなく、より適切なスタイルが他にもあることを理解しています(それらを指定してくれてありがとう)。

PSコードを大いに誓わないでください。私の問題は、他の人に自分のコードをほとんど見せなかったことです。

個人的なブログで



All Articles