以下示例基于 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()
,渲染()
?
最佳答案
对...这种实例化函数并在其上悬挂附加方法的特殊风格的问题在于,变量必须是实例化返回函数的函数作用域的一部分(bar
或饼
)。由于这些变量是内部变量,在此范围之外无法访问,因此在扩展实例时无法获取它们。
在进一步讨论之前,请注意您的实现有点偏离。首先,您在 console.log('bar created: ' + width + ' ' + height);
的位置,从语义上讲这是不正确的。这实际上并不是它被创建的地方,而是它被渲染的地方。它是在您调用 bar()
时创建的。
然后,当您渲染此图表时,您应该做的是,而不是 bar().width(200).render()
var barChart = bar().width(200);
d3.select('svg')
.append('g')
.call(barChart)
您不需要render()
。相反,my()
的主体是您的渲染。但是,根据 mbostocks 的建议,my()
应将 d3 选择作为参数,在本例中将是要附加的 g
元素。这是您链接到的可重用图表教程的右侧;重新阅读一下,您就会明白我的意思。
最后,回答一下你的实际问题。我这样做的方法是使用 d3.rebind
。首先,您必须创建一个公共(public)基类,它具有内部 width
变量和 width()
getter/setter,如下所示:
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
,以便您可以调用 bar().width()
。 Here's a fiddle that works.
关于javascript - 跨 Javascript 代码共享 getter/setter 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25750109/