Static variables with a simple John Resig class template?

I mean this article .

In it, he defines a function that looks something like this:

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'); } }; } 

And then you can use it with something like this:

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

But now I want to initialize some static variables that should be available for all instances. How to do it?

+4
source share
6 answers

Well, the simplest approach is to define a static variable as a property of the prototype:

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

... but it will not behave like static properties in other languages:

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

Another way is to use the fact that properties can also be bound to functions:

 MyClass.xxx = 3; 

... but this narrows the ways of using this property (it cannot be called t1.xxx from the previous examples).

However, there is another way. You can define static properties as variables local to the init method, accessible using methods defined ... in this initialization method. ) Like this.
  init: function() { var xxx = 3; MyClass.prototype.getXXX = function() { return xxx; }; MyClass.prototype.setXXX = function(newXXX) { xxx = newXXX; } } 

Then all this property can be used as follows:

  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! 

And here is the violin .

UPDATE: this approach is better to use, I suppose, when we need to work with a container (type) of data of a static class that should be used by all objects, but we do not know exactly what can actually be stored in this container. Then we use only two functions - getStatic and setStatic - to store and retrieve data using string keys or some other identifiers. It may seem a little confusing, and it is, but I think it may be worth the effort. )

+3
source

Just add it to MyClass .

 MyClass.myVariable = 42; 

This is not very static in the sense of Java / C #, but it gives the same effect.

+2
source

If you don't care about browser support, you can also use WeakMap constructor / static property pairs. Here is an idea: http://jsfiddle.net/DfNNU/2/ . This requires MyClass.prototype.constructor , which you should not discard. So, you need to add back the prototype constructor: MyClass .

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

Use it as:

 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 
+1
source

I "solved" this problem using a naming convention.

I wanted to simplify the syntax of Class.extend({ }) , but also a way to declare โ€œstaticโ€ properties in it.

I chose the leading underline to declare a static property, although you could do whatever you liked.

Using:

 var myClass = Class.extend({ _staticProperty: 1337 , instanceProperty: 'foo' , instanceMethod: function() { } , ctor: function() { this.base(); } }); 

note I renamed init and this._super() from the source code

And the code:

 /* 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; }; })(); 
+1
source

I modified the John Resig class to provide an instance of the parent static members with a new class that adds the following:

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

Here's the fiddle .

 // This is a modified version of John Resig 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 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> 
0
source

Pass an optional list of static members in the 'extend' call. This method adds static properties (if any) to the "statics" attribute in the constructor function.

Code Changes

Changed as follows. These lines are added immediately after the 'dummy class constructor' code:

  if(staticProp) { Class.statics = []; for (var name in staticProp) { !Class.statics[name] && (Class.statics[name] = staticProp[name]); } } 

Added an additional argument "staticProp", added during the type declaration, to allow the introduction of static elements at this stage:

 Class.extend = function(prop,staticProp) { 

The script can be found here , contains some tests.

Examples of using

It can determine the statics at the time of type declaration, using the second optional constructor argument:

 var A = Class.extend({},{myStatic:1}); 

You can access / define the statics inside the instance method:

 var B = Class.extend({test:function(){B.statics.myStatic=2;}}); 

Or an externally instance:

 A.statics.myStatic=3; 

Example with requirejs:

Put the .js class in the baseUrl folder. An example of a new class definition. It is not necessary to specify the file of the new class in the same way as "var C" (ie C.js), but it is probably better for readability, therefore references to the name C in the methods of the class are aligned with any external links to its static elements :

 define(['Class'],function($) { var C = Class.extend({ init: function(params){ C.statics.myStatic++; // access static data } },{ myStatic: 123 }); return C; }); 

Another class in D.js refers to static data in class C:

 define(['Class', 'C'],function($,C) { var D = Class.extend({ init: function(params){ C.statics.myStatic++; // static data of another class } },{}); return D; }); 
0
source

All Articles