我试图使用mootools/Dojo
使用Javascript模拟Java的以下行为。需要使用类静态变量值初始化的实例变量。
Class xyz {
public static static_constants {
TEST_CONST1 : "abc";
}
private a = static_constants.TEST_CONST1;
}
我可以通过以下方式执行此操作,但随后com.example.test.static_constants.TEST_CONST1
将不再存在,因为我们已覆盖com.example.test
。但是如果之前没有定义com.example.test.static_constants.TEST_CONST1
,那么类中的赋值将失败。
com.example.test.static_constants.TEST_CONST1 = "abc";
var com.example.test = new Class ({
a : com.example.test.static_constants.TEST_CONST1
});
两种可行的解决方法:
var com.example.test = new Class ({
static_constants : {
TEST_CONST1 : "abc"
},
a : this.static_constants.TEST_CONST1
});
com.example.test.static_constants.TEST_CONST1 = "abc";
com.example.test.static_constants.TEST_CONST1 = "abc";
var com.example.test = new Class ({
a : com.example.test.static_constants.TEST_CONST1
});
com.example.test.static_constants.TEST_CONST1 = "abc";
我错过了什么?这两种方式对我来说似乎都不干净。必须有一个更简洁的方法来做到这一点(不使用扩展等 - 这将进一步打破课程。)
答案 0 :(得分:3)
我可以插话并阻止你。
JavaScript不是JAVA。现在你不需要使用JAVA这一事实并不意味着你需要将与它所拥有的命名空间和静态和模式相关的垃圾移到JavaScript上。在处理事务时,JavaScript有不同的模式。
在任何情况下,因为你没有问什么,在MooTools的组织的东西和类的最佳方式是,你只是想知道如何变异,并扩展现有的对象,就可以做到这一点的小厂:
var com = {
example: {
test: {
static_constants: {
TEST_CONST1: "abc"
}
}
}
};
Class.extend({
fromExisting: function(namespace, constructorObject){
return Object.append(new this(constructorObject), namespace);
}
});
// this is non-DRY. It kind of is Object.merge()
com.example.test = Class.fromExisting(com.example.test, {
a: com.example.test.static_constants.TEST_CONST1,
initialize: function(){
console.warn(this.a);
},
getStatic: function(what){
return com.example.test.static_constants[what];
}
});
var t = new com.example.test();
console.log(Object.getOwnPropertyNames(t)); // no static_constants
console.log(t.a);
console.log(com.example.test.static_constants);
com.example.test.static_constants.TEST_CONST1 = 'bbb';
console.log(t.a);
console.log(t.getStatic('TEST_CONST1'));
Class.fromExisting
将接受一些对象,它将其属性与类构造函数对象合并(但是静态,而不是原型) - 但它不能改变它在构造函数中扩展的obj(不能想想为什么现在,但是周六晚上。)
你真的应该只实现更合理的模块命名方法/命名空间 - 就像在AMD中一样,并在单独的配置对象上使用constants
。没有必要混合两个命名空间 - 或者实际上,当你使用AMD时,根本不需要命名空间(尽管你可以命名你的模块)。
请不要使用此工厂模式,只显示扩展类型等时灵活的mootools。
相反,你可以简单地 - 如上所述 - 只做Object.merge()
com.example.test = Object.merge(new Class({
a: com.example.test.static_constants.TEST_CONST1,
initialize: function(){
console.warn(this.a);
},
getStatic: function(what){
return com.example.test.static_constants[what];
}
}), com.example.test);
因为你正在使用一些狡猾的命名空间,你想看看扩展的Object Type(不是Object的原型),get / set工作得很深,Daniel Buchner试图降落它但被击落。
https://github.com/mootools/mootools-core/pull/2191/files
这些可能会消除从虚线字符串创建更深层名称空间的痛苦。现在开心吧。
答案 1 :(得分:1)
如果你是using AMD,你会define
一个模块而不创建像com.example.test
这样的全局对象链。 declare
的文档有a short section on static objects,但概念很简单:您可以将“额外内容”挂在您返回的模块之外。
如果您需要一个仅对其定义的模块可用的常量,只需使用常规变量。如果您需要访问模块的外部,只需将其挂起您返回的模块对象即可。这类似于你问题中的第一个方法,但是没有必要涉及一个丑陋的全局对象链。
答案 2 :(得分:1)
首先,我会在两个不同的问题中解决您的问题:
由于JS和Java之间的架构差异,无论你做什么都会有点难看。
这里的关键是你必须延迟尝试访问静态变量,直到实际创建实例。我不知道mootools(是initialize
吗?),但是在Dojo 1.9中,相关的方法被称为constructor
,所以我将在这个例子中使用它:
var makeMyClass = function(){
var clazz = new Class ({
instanceVal : null, // Don't know what to put here yet
constructor : function(){
/*
I know this looks weird that this property is ALSO
called "constructor", but it works in Dojo 1.9. Consult
your debugger to see if a similar tactic works in mootools.
*/
var selfClass = this.constructor;
// Remember that if staticVal is an object, you may-or-may-not want an independent copy
this.instanceVal = selfClass.staticVal;
}
});
clazz.staticVal = "Hello World";
return clazz;
};
var com.example.myClass = makeMyClass();
现在,如果修改com.example.myClass.staticScalarVal
,它应该影响将来构建的类,尽管IMO构建器或工厂设计模式会好得多。
这里的实现很大程度上取决于你想要的僵化/偏执,因为JS自然对动态变化非常宽容。所以这里只是一些想法:
如果要在访问未定义的常量时抛出错误(而不是返回undefined
并且在15步后失败),请考虑:
var createLightweightConstantHolder = function(){
// Because it's nestled in this method, we're protected from the evil outside world.
var constants = {
FOO : "hello",
BAR : [1,2,3]
};
return function(cname){
if(typeof cname == "undefined"){
// Gives all constants back at once, in case someone needs to iterate
return lang.clone(constants);
}else{
// Value of a particular thing
if(constants.hasOwnProperty(cname)){
return constants[cname];
}else{
throw "Constant '"+cname+"' does not exist.";
}
}
}
};
var stuff = createLightweightConstantHolder();
stuff("FOO"); // Returns "hello"
stuff("BAZ"); // Throws a descriptive exception
var copyOfUnderlyingValues = stuff();
这有点难看,因为你将常量名称作为字符串传递,但它会快速失败并阻止修改。
Object.freeze
这个使用了一个相对较新的“冻结”物体的功能。请注意,它仅冻结顶级对象以防止添加/删除/替换值。仍然可以对非标量进行更改。
var constants = {
FOO : "hello",
BAR : [1,2,3],
BAZ : {"x","y"}
};
constants = Object.freeze(constants);
/*
* Some things which do/don't work:
*/
constants.FOO; // Is "hello"
constants.FOO = "goodbye"; // Won't change. Depending on env and strict-mode, may throw an error or else silently fail.
constants.OOPS; // Is undefined, does NOT throw an error when access it.
constants.BAR.push(4); // DOES alter array items
constants.BAZ.x = "z"; // DOES alter object properties
这不适用于所有平台,请查看浏览器/环境兼容性图表。