6

この記事を参照しています。

その中で、彼は次のような関数を定義しています。

function makeClass() {
    return function _class() {
        if(this instanceof _class) {
            if(typeof this.init === 'function') {
                this.init.apply(this, arguments);
            }
        } else {
            throw new Error('Constructor called as a function');
        }
    };
}

そして、次のようなもので使用できます。

var MyClass = makeClass();

MyClass.prototype = {
    init: function(width, height) { ... },
    clear: function(ctx) {... },
    draw: function(ctx) { ... }
}

しかし今、すべてのインスタンスで共有する必要があるいくつかの静的変数を初期化したいと考えています。それ、どうやったら出来るの?

4

6 に答える 6

4

最も簡単なアプローチは、静的変数をプロトタイププロパティとして定義することです。

MyClass.prototype.xxx: 3, // ...
var t1 = new MyClass();
console.log(t1.xxx); // 3

...しかし、他の言語の静的プロパティが通常行うようには動作しません。

var t2 = new MyClass();
t2.xxx = 5;
console.log(t1.xxx); // still 3 :(

もう1つの方法は、プロパティが関数にもアタッチされる可能性があるという事実を使用することです。

MyClass.xxx = 3;

...しかし、それはこのプロパティを使用する方法を狭めます(前の例から呼び出すことはできませんt1.xxx)。

ただし、別の方法があります。このinitメソッドでも、静的プロパティを、メソッドに対してローカルで、initメソッドからアクセス可能で、定義された変数として定義できます。) このような。

   init: function() {
      var xxx = 3;
      MyClass.prototype.getXXX = function() {
         return xxx;
      };
      MyClass.prototype.setXXX = function(newXXX) {
         xxx = newXXX;
      }
   }

そうすれば、すべての人がこのプロパティを次のように簡単に使用できます。

  var t1 = new MyClass();
  var t2 = new MyClass();
  console.log(t1.getXXX()); // 3
  console.log(t2.getXXX()); // 3
  t1.setXXX(5);
  console.log(t1.getXXX()); // 5 now
  console.log(t2.getXXX()); // 5 as well, behold the power of closures!

そして、これが使用されたフィドルです。

更新:このアプローチは、すべてのオブジェクトで共有される静的クラスデータの(一種の)コンテナーを操作する必要がある場合に使用する方が適切だと思いますが、実際に何ができるかは正確にはわかりません。このコンテナに保存されます。次に、2つの関数(getStaticおよび)を使用setStaticして、文字列キーまたはその他の識別子によってデータを格納および取得します。少し紛らわしいかもしれませんが、努力する価値はあると思います。)。

于 2012-06-23T21:06:36.137 に答える
3

それを自分自身に追加するだけMyClassです。

MyClass.myVariable = 42;

Java/C# の意味では実際には静的ではありませんが、同じ効果が得られます。

于 2012-06-23T20:59:30.943 に答える
2

命名規則を使用して、この問題を「解決」しました。

構文の利便性だけでClass.extend({ })なく、構文内で「静的」プロパティを宣言する方法も必要でした。

静的プロパティを宣言するために先頭のアンダースコアを選択しましたが、好きなことを行うことができます。

使用法:

var myClass = Class.extend({

    _staticProperty: 1337

    , instanceProperty: 'foo'
    , instanceMethod: function() { }

    , ctor: function() {
        this.base();
    }
});

元のコードから名前を変更initしたことに注意してくださいthis._super()

そしてコード:

/* Simple JavaScript Inheritance
 * Modified by Andrew Bullock http://blog.muonlab.com to add static properties
 * By John Resig http://ejohn.org/
 * MIT Licensed.
 */
// Inspired by base2 and Prototype
(function () {
    var initializing = false, fnTest = /xyz/.test(function () { xyz; }) ? /\bbase\b/ : /.*/;

    // The base Class implementation (does nothing)
    this.Class = function () { };

    // Create a new Class that inherits from this class
    Class.extend = function (prop) {
        var base = this.prototype;

        // Instantiate a base class (but only create the instance,
        // don't run the init constructor)
        initializing = true;
        var prototype = new this();
        initializing = false;

        // The dummy class constructor
        function Class() {
            // All construction is actually done in the ctor method
            if (!initializing && this.ctor)
                this.ctor.apply(this, arguments);
        }

        // Copy static properties from base
        for (var name in this) {
            if (name.substr(0, 1) == '_')
                Class[name] = this[name];
        }

        // Copy the properties over onto the new prototype
        for (name in prop) {
            // Check if we're overwriting an existing function
            if (typeof prop[name] == "function" && typeof base[name] == "function" && fnTest.test(prop[name])) {
                prototype[name] = (function(name, fn) {
                    return function() {
                        var tmp = this.base;

                        // Add a new .base() method that is the same method
                        // but on the super-class
                        this.base = base[name];

                        // The method only need to be bound temporarily, so we
                        // remove it when we're done executing
                        var ret = fn.apply(this, arguments);
                        this.base = tmp;

                        return ret;
                    };
                })(name, prop[name]);
            } else if (name.substr(0, 1) == '_') {
                Class[name] = prop[name];
            } else {
                prototype[name] = prop[name];
            }
        }

        // Populate our constructed prototype object
        Class.prototype = prototype;

        // Enforce the constructor to be what we expect
        Class.prototype.constructor = Class;

        // And make this class extendable
        Class.extend = arguments.callee;

        return Class;
    };
})();
于 2014-05-04T16:48:57.830 に答える
1

ブラウザーのサポートを気にしない場合はWeakMap、コンストラクターと静的プロパティのペアを使用することもできます。ここにアイデアがあります: http://jsfiddle.net/DfNNU/2/。これには が必要MyClass.prototype.constructorであり、破棄してはなりません。constructor: MyClassしたがって、プロトタイプに追加し直す必要があります。

var statics = (function() {
    var map = new WeakMap;
    return function(inst) {
        var ctor = inst.constructor;
        return map.get(ctor) || map.set(ctor, {});
    };
})();

次のように使用します。

var a = function() {};
var b = function() {};

var inst1 = new a;
var inst2 = new a;
var inst3 = new b;

statics(inst1).foo = 123;
statics(inst3).foo = 456;

console.log( statics(inst1).foo );  // 123
console.log( statics(inst2).foo );  // 123
console.log( statics(inst3).foo );  // 456
于 2012-06-23T21:16:30.570 に答える
1

John Resig のクラスを変更して、親の静的メンバーを新しいクラスにコピーできるようにしました。これにより、次のように追加されます。

    for (var name in this) {
        if (!Class[name]) {
            Class[name] = this[name];
        }
    }

ここにフィドルがあります。

// This is a modified version of John Resig's simple inheritence class to add copying of static methods
// The new code is the for loop commented with "add in the static members"

/* Simple JavaScript Inheritance
 * By John Resig http://ejohn.org/
 * MIT Licensed.
 */
// Inspired by base2 and Prototype
(function(){
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
 
  // The base Class implementation (does nothing)
  this.Class = function(){};
 
  // Create a new Class that inherits from this class
  Class.extend = function(prop) {
    var _super = this.prototype;
   
    // Instantiate a base class (but only create the instance,
    // don't run the init constructor)
    initializing = true;
    var prototype = new this();
    initializing = false;
   
    // Copy the properties over onto the new prototype
    for (var name in prop) {
      // Check if we're overwriting an existing function
      prototype[name] = typeof prop[name] == "function" &&
        typeof _super[name] == "function" && fnTest.test(prop[name]) ?
        (function(name, fn){
          return function() {
            var tmp = this._super;
           
            // Add a new ._super() method that is the same method
            // but on the super-class
            this._super = _super[name];
           
            // The method only need to be bound temporarily, so we
            // remove it when we're done executing
            var ret = fn.apply(this, arguments);        
            this._super = tmp;
           
            return ret;
          };
        })(name, prop[name]) :
        prop[name];
    }
    
    // The dummy class constructor
    function Class() {
      // All construction is actually done in the init method
      if ( !initializing && this.init )
        this.init.apply(this, arguments);
    }
   
    // Populate our constructed prototype object
    Class.prototype = prototype;
   
    // Enforce the constructor to be what we expect
    Class.prototype.constructor = Class;

    //add in the static members
    for (var name in this) {
    		if (!Class[name]) {
		        Class[name] = this[name];
        }
    }

    // And make this class extendable
    Class.extend = arguments.callee;
   
    return Class;
  };
})();

function addText(text) {
    document.getElementById('greetings').innerHTML = document.getElementById("greetings").innerHTML + '<br>' + text;
}

//parent class with a prototype method and two static methods
var Parent = Class.extend({
  hello: function () {
    addText('parent.hello');
  }
});  
Parent.static = function() {
  addText('Parent.static');
}
Parent.overrideStatic = function() {
  addText('Parent.overrideStatic');
}

//child class that overrides one of the parent's static methods
var Child = Parent.extend();
Child.overrideStatic = function() {
  addText('Child.overrideStatic');
}

var parent = new Parent();
parent.hello();
Parent.static();

var child = new Child();
child.hello();   //should output parent.hello
Child.static();  //should output Parent.static
Child.overrideStatic();
<div id="greetings"></div>

于 2016-03-29T00:11:43.127 に答える