做一些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
无法看到它的外部封闭,如果这有任何意义的话。就像将它放入一个只能 查看函数内部变量的函数。这样我就可以在移动代码之前弄清楚任何破坏的引用。
当然我不必这样做,但我只是好奇,如果可能的话。我觉得我只是不知道正确的术语,或者我已经发现它了。
答案 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
)仍然依赖于关闭d3
和contextShowing
,但不依赖于关闭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
值。