我可以强制封闭与其父/外隔离吗?

时间:2014-05-14 17:04:22

标签: javascript

做一些D3的事情,决定在饼图中添加一个上下文菜单。

  // this code may not be complete
  if (!!readOnly) {  
    if (this.link != null) {
      if (d3.select("div#contextMenu").empty()) {
        contextMenu = d3.select(selector).append("div").attr("id", 'contextMenu').attr("class", "rounded");
      }
      d3.selectAll("" + selector + " svg g.slice").on("click", function(object, index) {
        return contextMenu.style("visibility", "hidden");
      }); 
      d3.selectAll("" + selector + " svg g.slice").on("contextmenu", function(object, index) {
        var position;
        if (!contextShowing) {
          position = d3.mouse(this);
          tooltip.style("visibility", "hidden");
          return contextMenu.style("visibility", "visible");
        }
      });
    }
  } 

现在好了,我已经让它在这个图中运行了,我想通过将它放在原型中将它添加到其他图形中。我的第一步是将所有这些代码放在一个函数中,如下所示:

drawContextMenu = function(selector) {
  if (!!readOnly) {  
     // etc...
  } 
};
drawContextMenu(selector); 

然后,一旦我使用了新功能,我就会将drawContextMenu移动到原型中。

过去当我做过这样的事情时,我遇到了很多运行时错误,因为将函数移动到另一个闭包中会打破一堆变量查找。所以我想我想让drawContextMenu无法看到它的外部封闭,如果这有任何意义的话。就像将它放入一个只能 查看函数内部变量的函数。这样我就可以在移动代码之前弄清楚任何破坏的引用。

当然我不必这样做,但我只是好奇,如果可能的话。我觉得我只是不知道正确的术语,或者我已经发现它了。

2 个答案:

答案 0 :(得分:2)

如果我们的目标是真正实现一个功能并将其从创建它的范围中删除,那么我就不会看到其他解决方案而不是获取其代码并重新创建它。

可以这样做:

var a = "some shadowed value";
function outer(){
  var a = "value from normal scope";
  return function(){
    return a;
  }  
}
var child = outer();
console.log(child()); // value from normal scope
var orphan = new Function(child.toString().match(/\{([\w\W]*)\}/m)[1]);
console.log(orphan()); // some shadowed value

当然......这可能不应该......但正如你所说的那样"只是好奇它是否可能" 那么这是我认为的有效答案;)


说明:

  • child.toString()是函数("function(){ some code }"
  • 的文本
  • /\{([\w\W]*)\}/m是一个正则表达式,它位于括号内("some code"),由于有多行(因此[\w\W]*
  • ,它有点棘手
  • new Function("some code")使用给定正文
  • 创建一个新函数

答案 1 :(得分:1)

这里通常的解决方案是" builder"用于构建回调的函数:

// Somewhere nicely contained (not deeply nested)
function createContextMenuRenderer(menu, tt) {
  return function(object, index) {
    var position;
    if (!contextShowing) {
      position = d3.mouse(this);
      tt.style("visibility", "hidden");
      return menu.style("visibility", "visible");
    }
  };
}

然后使用它:

d3.selectAll("" + selector + " svg g.slice").on("contextmenu", createContextMenuRenderer(contextMenu, tooltip));

请注意,上面的构建器(createContextMenuRenderer)仍然依赖于关闭d3contextShowing,但不依赖于关闭contextMenu或{{ 1}}。

现在让我们假设您希望tooltip不要关闭createContextMenuRenderer,而是使用 contextShowing的任何值当contextShowing事件触发时。 (我们仍然会将其关闭contextmenu。)为此,您需要能够回溯到您正在使用构建器的上下文中的内容:

d3

使用它:

function createContextMenuRenderer(menu, tt, getContextShowing) {
  return function(object, index) {
    var position;
    if (!getContextShowing()) {
      position = d3.mouse(this);
      tt.style("visibility", "hidden");
      return menu.style("visibility", "visible");
    }
  };
}

d3.selectAll("" + selector + " svg g.slice").on("contextmenu", createContextMenuRenderer(contextMenu, tooltip, function() { return contextShowing; }) ); 是可重复使用的,您只需将一个函数传递给它即可获得相关的createContextMenuRenderer值。