目前我正在使用以下代码为我的班级定义getter和setter:
Object.defineProperty(FPProject.prototype, 'name', {
get: function() { return this.get('name'); },
set: function(aValue) {return this.set('name', aValue);}
});
Object.defineProperty(FPProject.prototype, 'code', {
get: function() { return this.get('code'); },
set: function(aValue) {return this.set('code', aValue);}
});
Object.defineProperty(FPProject.prototype, 'clientName', {
get: function() { return this.get('clientName'); },
set: function(aValue) {return this.set('clientName', aValue);}
});
Object.defineProperty(FPProject.prototype, 'client', {
get: function() { return this.get('client'); },
set: function(aValue) {return this.set('client', aValue);}
})
我认为我可以将此代码优化为以下内容:
var fields = ['name','code','clientName','client'];
for (var i = 0; i < fields.length; i ++ ) {
Object.defineProperty(FPProject.prototype, fields[i], {
get: function() { return this.get(fields[i]); },
set: function(aValue) {return this.set(fields[i], aValue);}
});
}
但它不起作用!我没有控制台错误,只是无法设置属性...... ???
答案 0 :(得分:3)
当你的循环结束时,i
变量将等于fields.length
,稍后调用的set
函数将使用此值。
尝试使用闭包捕获当前索引元素:
for (var i = 0; i < fields.length; i ++ ) {
(function (index) {
Object.defineProperty(FPProject.prototype, fields[index], {
get: function() { return this.get(fields[index]); },
set: function(aValue) {return this.set(fields[index], aValue);}
});
}(i));
}
答案 1 :(得分:3)
这是经典的闭包问题。您在循环中创建的函数对i
变量具有持久引用,而不是它的副本。因此,当您的访问者函数被调用时,i
为fields.length
,因此他们从fields[i]
获得的值为undefined
。
通常的解决方案是构建器功能:
var fields = ['name','code','clientName','client'];
for (var i = 0; i < fields.length; i ++ ) {
buildProperty(FPProject.prototype, fields[i]);
}
function buildProperty(obj, name) {
Object.defineProperty(obj, name, {
get: function() { return this.get(name); },
set: function(aValue) {return this.set(name, aValue);}
});
}
我总是把它做成一个漂亮,清晰,独立的功能,以便A)我们不会在每个循环中重新创建它,并且B)它更容易调试,理解和重用。
现在,访问者关闭了buildProperty
及其obj
和name
参数调用的上下文,这些参数不会发生变化,因此当他们发生变化时他们称他们使用正确的name
。
答案 2 :(得分:3)
另外两个答案工作正常(我赞成它们),但我想我会补充说,这是一个数组迭代器方法派上用场的地方,因为使用它的任务创建了一个函数闭包自动解决此索引问题的操作:
['name','code','clientName','client'].forEach(function(item) {
Object.defineProperty(FPProject.prototype, item, {
get: function() { return this.get(item); },
set: function(aValue) {return this.set(item, aValue);}
});
});
当然,你必须注意.forEach()
的浏览器兼容性,它需要IE9或更高版本或者polyfill(显示为here)。
仅供参考,这种设计模式由流行的第三方库使用,因为它是一种非常紧凑的方式,可以运行相同的代码,并通过它运行几个不同的值。