更新2017-01-17
随着 D3 的发布v4这个问题已经消失了(变更日志):
选择不再使用 Array 的子类原型链注入;它们现在是普通对象,提高了性能。
和APIdocs明确指出:
# d3.选择() <>
[…]此功能还可用于测试选择(instanceof d3.selection
)
使用新版本,以下代码实际上在所有浏览器中都会计算为 true:
d3.select() instanceof d3.selection // true in Chrome, FF, IE
对于所有仍在使用 v3 的人,下面的原始答案提供了问题的分析和解决方法。
Problem
由于 D3 的内部工作原理,每个支持的浏览器Object.prototype.__proto__将打印true
,而浏览器缺乏支持__proto__
将打印false
。检查兼容性列表很明显,IEfalse。因此,您将无法使用instanceof d3.selection
检查 IE已知问题与D3,但它已关闭并且不会得到修复。
Analysis
来自 D3 的 github 存储库:
selection/selection.js
看一下定义d3.select()这是您的呼叫的入口点:
d3.select = function(node) {
// ... removed for brevity
return d3_selection([group]);
};
这最终将返回调用的结果d3_selection(),这又将子类化d3_selectionPrototype = d3.selection.prototype
.
function d3_selection(groups) {
d3_subclass(groups, d3_selectionPrototype);
return groups;
}
core/subclass.js
最后,实施d3_subclass()提供了问题的答案:
var d3_subclass = {}.__proto__?
// Until ECMAScript supports array subclassing, prototype injection works well.
function(object, prototype) {
object.__proto__ = prototype;
}:
// And if your browser doesn't support __proto__, we'll use direct extension.
function(object, prototype) {
for (var property in prototype) object[property] = prototype[property];
};
它检查浏览器是否支持Object.prototype.__proto__
通过检查是否存在__proto__
空对象上的访问器属性{}
。如果浏览器支持,D3将直接分配原型,从而使其成为d3.selection
。否则,原型的所有属性将被复制到要返回的对象,而无需显式设置原型。在这种情况下,您的表达式将计算为false
.
解决方法
Because d3.selection提供作为扩展选择功能的一种方法,您可以通过添加新属性来实现解决方法d3.selection
正如上面所解释的,可以通过任何选择来访问它,无论是通过原型设计还是通过复制属性。
// Include this at the start of your script to include the
// property in any selection created afterwards.
d3.selection.prototype.isD3Selection = true;
console.log(d3.select(document.body).isD3Selection); // true in any browser