在学习D3.js时,我遇到了blog post,解释了它可重复使用的代码单元背后的主要设计模式。我已经复制了下面的相关代码。下面给出的模式的方式与D3代码库和插件(example)中使用的方式完全相同。
我对此代码的一个问题是它对属性有如此多的复制粘贴。 JavaScript是一种函数式语言,我以为我能够重新考虑样板代码,但我想不出办法。 arguments
和value
参数很容易传递给常用函数,但我找不到保留对width
和height
属性的引用的方法。< / p>
function chart() {
var width = 720, // default width
height = 80; // default height
function my() {
// generate chart here, using `width` and `height`
}
my.width = function(value) {
if (!arguments.length) return width;
width = value;
return my;
};
my.height = function(value) {
if (!arguments.length) return height;
height = value;
return my;
};
return my;
}
这就是在实际的D3代码库中完成它的事实让我想知道是否可以进行重新分解,但我希望这只是一个问题,而不是一个高优先级的问题(而且新的贡献者是这样做,因为这是以前做过的。)
我正在寻找的是基本上用以下内容替换每个访问者的身体:
my.height = function(value) {
return getSet(arguments, value, whatever);
};
调用还有一些样板,但至少逻辑是集中的,如果需要,只能在一个地方更新。
答案 0 :(得分:1)
如果您在getSet
的范围内定义chart
,它也可以访问已关闭的变量。问题是,您无法通过名称字符串访问这些变量(除非您使用某种eval
)。
您可以通过将所有私有变量包装在对象未经测试中来避免这种情况:
function chart() {
var props = {
width: 720, // default width
height: 80 // default height
}
function my() {
// generate chart here, using `width` and `height`
}
my.height = function(value) {
// Call getSet with current my instance as this,
// 'height' as the first argument, then value
return getSet.apply(this, arguments.slice().unshift('height'));
};
// Works just like your current accessors, on the props object
function getSet(property, value) {
if (arguments.length > 1) return props[property];
props[property] = value;
return this;
}
return my;
}
问题是这并不比为每个属性编写几个类似的访问器短。您当前的访问者使私有变量几乎是公开的,那么为什么不放弃它们并使用公共变量呢?
答案 1 :(得分:0)
已经提供的另一种解决方案是定义一个&#39;属性&#39;返回函数的函数,例如
function property (v) {
return function (_) {
if(!arguments.length)
return v;
v = _;
return this;
};
}
所以你可以说:
function chart() {
chart.width = property.call(chart, 500);
chart.height = property.call(chart, 500);
chart.render = function() {
//render logic goes here
};
return chart;
}
我不能完全赞同这一点 - 我认为来源实际上是Mike Bostock(但我找不到原帖的链接)
我使用这个&#39;属性&#39;在我的许多模块中都有功能 - 它可以节省很多烦人的打字。当传入的值发生变化时,您可以轻松扩充它以发出事件。