我正在用一个围绕getter/setter方法有大量样板的对象创建面向闭包的对象。有没有办法将这些属性声明为getter/setter而不用重复这么多?
目前我有:
var test = function(){
var width = 10;
var height = 10;
return {
width: {get: function(){return width;}, set: function(_){width=_;}},
height: {get: function(){return height;}, set: function(_){height=_;}},
}
}
,但我想要更像:
var test = function(){
var width = 10;
var height = 10;
return {
width: getset(width)
height: getset(height),
}
}
我想写这样一个函数:
var test = function(){
var getset = function(val){
return {
get: function(){
console.log('getting');
return val
},
set: function(_){
console.log('besetted');
param=_
},
}
}
var width = 10;
var height = 10;
return {
width: getset(width),
height: getset(height),
}
}
,但这不起作用;变量没有被正确地覆盖。最好的方法是什么?是否有相应的语言特性?
给你:
var test = function(){
var getset = function(value){
var val = value;
return {
get: function(){
console.log('getting');
return val
},
set: function(_){
console.log('besetted');
val=_
},
}
}
var width = 10;
var height = 10;
return {
width: getset(width),
height: getset(height),
}
}
关于闭包要记住的一件事——你需要一个变量,这个变量既可以在内部函数的作用域内访问,也可以在外部访问。
你想要的是:
var test = function()
{
var
width = 10,
height = 10;
this.setWidth = function(_w)
{
width = _w;
};
this.getWidth = function()
{
return width;
};
// etc.
}
现在你有了一个可以实例化的"类":
var testObj = new test();
console.log(testObj.getWidth()); // 10
testObj.setWidth(20);
console.log(testObj.getWidth()); // 20
解释:JS没有"私有"或"公共"属性/方法。相反,公共对象属性/方法被附加到this
,而私有"属性"被声明为函数变量,如上所示。
由于JS的闭包逻辑,类方法总是可以访问函数变量,而其他组件无法看到它们。
这样如何:
function GetSet(value) = {
this.myValue = value;
var that = this;
this.getset = function(setter){
if (setter === undefined){
return that.myValue;
} else {
that.myValue = setter;
}
}
}
所以你替换:
return {
width: getset(width),
height: getset(height),
}
:
return {
width: new GetSet(width),
height: new GetSet(height)
}
…变量没有被正确覆盖. ...是否有相应的语言特性?
语言本身并不直接提供特性。但是,像往常一样,可以使用各种基于函数的模式,如闭包作为穷人的助手和工厂模块。
出于代码重用的原因,我个人会模块化一个辅助函数,该函数通常解决基于键值配置的getter和setter的创建问题。这样一来,人们就不必仅仅关注于实现工厂/构造器,而这些工厂/构造器必须解决主要任务。
除了大多数人怀疑的架构,有时偏执地试图封装每个对象状态没有很好的理由,我在此提供一个概念性的解决方案…[paranoid]
, [Paranoiac]
, kind test
…
var paranoid = (function () {
var
module,
firstCharToUpperCase = function (str) {
var
list = str.split(""),
char = list.shift()
;
list.unshift(char.toUpperCase());
return list.join("");
},
createKeyForSetter = function (key) {
return ["set", firstCharToUpperCase(key)].join("");
},
createKeyForGetter = function (key) {
return ["get", firstCharToUpperCase(key)].join("");
},
setTargetValue = function (target, key, value) {
return (target[key] = value);
},
getTargetValue = function (target, key) {
return target[key];
},
createAndAggregateGetterAndSetterForEachKeyValueAndTarget = function (collector, key) {
collector.target[createKeyForSetter(key)] = function (value) {
//return setTargetValue(collector.config, key, value);
setTargetValue(collector.config, key, value);
//return collector.target;
return this;
};
collector.target[createKeyForGetter(key)] = function () {
return getTargetValue(collector.config, key);
};
return collector;
}
;
module = {
aggregateGettersAndSetters: createAndAggregateGetterAndSetterForEachKeyValueAndTarget
};
return module;
}());
…
var Paranoiac = (function (global) {
var
Constructor,
factory,
object_keys = global.Object.keys,
createAndAggregateGetterAndSetterForEachKeyValueAndTarget = global.paranoid.aggregateGettersAndSetters,
createInstanceFromConfig = function (config) {
var instance = null;
if ((config != null) && (object_keys(config).length >= 1)) {
instance = new Constructor(config);
}
return instance;
},
isInstance = function (type) {
return (
(type != null)
&& (type instanceof Constructor)
);
}
;
Constructor = function Paranoiac (config) {
var
instance = this
;
object_keys(config).reduce(createAndAggregateGetterAndSetterForEachKeyValueAndTarget, {
config: config,
target: instance
});
return instance;
};
factory = {
create : createInstanceFromConfig,
isParanoiac : isInstance
};
return factory;
}(window || this));
…
var
p1 = Paranoiac.create({width: 55, height: 66}),
p2 = Paranoiac.create({width: 44, height: 77}),
p3 = Paranoiac.create({width: 33, height: 99})
;
console.log("Object.keys(p1) - ", Object.keys(p1));
console.log("Object.keys(p2) - ", Object.keys(p2));
console.log("Object.keys(p3) - ", Object.keys(p3));
console.log("p1.getWidth(), p1.getHeight() - ", [p1.getWidth(), p1.getHeight()]);
console.log("p2.getWidth(), p2.getHeight() - ", [p2.getWidth(), p2.getHeight()]);
console.log("p3.getWidth(), p3.getHeight() - ", [p3.getWidth(), p3.getHeight()]);
console.log('p1.setWidth("5"), p1.setHeight("6") - ', [p1.setWidth("5"), p1.setHeight("6")]);
console.log("p1.getWidth(), p1.getHeight() - ", [p1.getWidth(), p1.getHeight()]);
console.log("p2.getWidth(), p2.getHeight() - ", [p2.getWidth(), p2.getHeight()]);
console.log("p3.getWidth(), p3.getHeight() - ", [p3.getWidth(), p3.getHeight()]);
console.log('p2.setWidth("4"), p2.setHeight("7") - ', [p2.setWidth("4"), p2.setHeight("7")]);
console.log('p3.setWidth("3"), p3.setHeight("9") - ', [p3.setWidth("3"), p3.setHeight("9")]);
console.log("p1.getWidth(), p1.getHeight() - ", [p1.getWidth(), p1.getHeight()]);
console.log("p2.getWidth(), p2.getHeight() - ", [p2.getWidth(), p2.getHeight()]);
console.log("p3.getWidth(), p3.getHeight() - ", [p3.getWidth(), p3.getHeight()]);
console.log("Paranoiac.isParanoiac(p1) - ", Paranoiac.isParanoiac(p1));
console.log("Paranoiac.isParanoiac(p2) - ", Paranoiac.isParanoiac(p2));
console.log("Paranoiac.isParanoiac(p3) - ", Paranoiac.isParanoiac(p3));
console.log("Paranoiac.isParanoiac() - ", Paranoiac.isParanoiac());
console.log("Paranoiac.isParanoiac({}) - ", Paranoiac.isParanoiac({}));