javascript - 跨 Javascript 代码共享 getter/setter 函数

标签 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()渲染()

最佳答案

对...这种实例化函数并在其上悬挂附加方法的特殊风格的问题在于,变量必须是实例化返回函数的函数作用域的一部分(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/

相关文章:

c++ - 无法将子类实例作为参数而不是父类(super class)传递

javascript - 带图例的 D3 等值线图

javascript - D3 缩放不断地向下和向右缩放 SVG,我该如何解决这个问题?

Javascript - 奇怪的正则表达式行为

python - 如何重写两个相互调用的方法,同时使用 super() 访问基类方法?

JavaScript 提交表单不包括字段

php - PHP 类中的 "Transient"属性?

javascript - 选择特定 JSON 键的值进行求和

javascript - 无论证书有效性如何,我的 node.js https 客户端始终有效

javascript - Box2dweb - 绳索接头不起作用