我指的是this article。
在其中,他定义了一个看起来像这样的函数:
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) { ... }
}
但是现在我想初始化一些应该在所有实例中共享的静态变量。我该怎么做?
答案 0 :(得分:3)
嗯,最简单的方法是将静态变量定义为原型属性:
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 :(
另一种方法是使用属性也可以附加到函数的事实:
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!
这里使用了a fiddle。
更新:我想,当我们需要使用静态类数据的(某种)容器时,可以更好地使用这种方法,即所有对象共享 - 但我们并不确切知道实际上可以存储在这个容器中。然后我们只使用两个函数 - getStatic
和setStatic
- 来按字符串键或其他标识符存储和检索数据。它可能看起来有点令人困惑,但它确实值得努力。 )
答案 1 :(得分:2)
只需将其添加到MyClass
本身。
MyClass.myVariable = 42;
它在Java / C#意义上并不是静态的,但会给你带来同样的效果。
答案 2 :(得分: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
答案 3 :(得分:1)
我"解决了#34;通过使用命名约定来解决这个问题。
我希望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;
};
})();
答案 4 :(得分:0)
我修改了John Resig的类,以便将父级静态成员的副本提供给新类,后者添加了这个:
for (var name in this) {
if (!Class[name]) {
Class[name] = this[name];
}
}
这是fiddle。
// 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>
答案 5 :(得分:0)
在呼叫&#39;扩展&#39;中传入可选的静态成员列表。此方法将静态属性(如果有)添加到“静态”属性中。构造函数的属性。
代码更改
更改如下。这些行刚刚在&#39; dummy类构造函数之后添加&#39;代码:
if(staticProp) {
Class.statics = [];
for (var name in staticProp) {
!Class.statics[name] && (Class.statics[name] = staticProp[name]);
}
}
另一个参数&#39; staticProp&#39;在声明类型时添加,以便在此阶段引入静态成员:
Class.extend = function(prop,staticProp) {
可以找到一个小提琴here,包括一些测试。
使用示例
可以使用第二个可选的构造函数参数在类型声明时定义静态:
var A = Class.extend({},{myStatic:1});
可以在实例方法中访问/定义静态:
var B = Class.extend({test:function(){B.statics.myStatic=2;}});
或者来自实例外:
A.statics.myStatic=3;
requirejs示例:
将Class.js放在baseUrl文件夹中。示例新类定义。不必将新类的文件命名为与&#39; var C&#39;相同。 (即C.js)但可能更好的可读性,因此在类的方法中对C名的引用与其静态成员的任何外部引用对齐:
define(['Class'],function($) {
var C = Class.extend({
init: function(params){
C.statics.myStatic++; // access static data
}
},{
myStatic: 123
});
return C;
});
D.js中的另一个类引用了C类中的静态数据:
define(['Class', 'C'],function($,C) {
var D = Class.extend({
init: function(params){
C.statics.myStatic++; // static data of another class
}
},{});
return D;
});