在Javascript代码中共享getter / setter函数

时间:2014-09-09 16:55:24

标签: javascript inheritance d3.js prototypal-inheritance

以下示例基于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()

1 个答案:

答案 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(),以便您可以致电myHere's a fiddle that works.