以下示例基于Mike Bostock's reusable charts proposal。
给出两个函数(bar()
和pie()
),每个函数生成一个不同类型的图表:
function bar() {
var width = 720, // default width
height = 80; // default height
function my() {
console.log('bar created: ' + width + ' ' + 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;
};
my.render = function() {
my();
return my;
};
return my;
}
function pie() {
var width = 720, // default width
height = 80; // default height
function my() {
console.log('pie created: ' + width + ' ' + 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;
};
my.render = function() {
my();
return my;
};
return my;
}
我可以通过链接方法调用这些函数:
bar().width(200).render(); // bar created: 200 80
pie().height(300).render(); // pie created 720 300
有没有办法在我的getter和setter方法相同的地方对这些进行编码?例如,我计划让每个中的width()
函数完全相同。如何使bar()
和pie()
函数继承共享函数,例如width()
,height()
,render()
?
答案 0 :(得分:2)
正确...关于这种特定样式的实例化函数和挂起其他方法的事情是,变量必须是实例化返回函数的函数范围的一部分(bar
或{ {1}})。由于这些变量在内部且在此范围之外无法访问,因此在扩展实例时无法获得这些变量。
在进一步说明之前,请注意您的实施有点偏差。首先,在pie
处,语义上的错误。这实际上并不是它创造的地方,而是它所呈现的地方。它是在您拨打console.log('bar created: ' + width + ' ' + height);
时创建的。
然后,当您渲染此图表时,而不是bar()
您应该做的事情,例如。
bar().width(200).render()
您不需要var barChart = bar().width(200);
d3.select('svg')
.append('g')
.call(barChart)
。相反,render()
的正文是你的渲染。但是,根据mbostocks建议,my()
应该将d3选择作为参数,在此示例中将是附加的my()
元素。这是您链接到的可重用图表教程的权利;重新阅读它,你就会明白我的意思。
最后,回答你的实际问题。我这样做是使用d3.rebind
。首先,您必须创建一个具有内部g
变量和width
getter / setter的公共基类,如下所示:
width()
接下来,您希望function base() {
var width;
function my(selection) {
console.log('base: ' + width);
}
my.width = function(value) {
if (!arguments.length) return width;
width = value;
return my;
};
return my;
}
(和bar
)基本上扩展基数,如下所示:
pie
最后一行,将function bar() {
var _base = base(); // instantiate _base, which has width() method
function my(selection) {
// In here, if you want to get width, you call `_base.width()`
// and, if there's some shared rendering functionality you want
// to put in base, you can run it with `selection.call(_base)`
}
d3.rebind(my, _base, 'width'); // make width() a function of my
return my;
}
复制到width()
,以便您可以致电my
。 Here's a fiddle that works.