d3.IElection中的选择类型检查

ᆼᆺᆼ*_*ᆼᆺᆼ 3 d3.js

如何检查给定对象是否是一个d3选择?

以下代码true在Chrome和Firefox中打印,但false在Internet Explorer中:

console.log(d3.select(document.body) instanceof d3.selection)
Run Code Online (Sandbox Code Playgroud)

alt*_*lus 6

更新2017-01-17

随着D3 v4的发布,这个问题已经消失了(changelog):

选择不再使用原型链注入子类化Array ; 它们现在是普通物体,提高了性能.

API 文档明确指出:

# d3.selection()<>

[...]此功能也可用于测试选择(instanceof d3.selection)

使用新版本,以下代码实际上将在所有浏览器中评估为true:

d3.select() instanceof d3.selection   // true in Chrome, FF, IE
Run Code Online (Sandbox Code Playgroud)

对于仍然在v3上的所有人,下面的原始答案都有针对该问题的分析和解决方法.


问题

由于D3的内部工作原理,每个支持的浏览器Object.prototype.__proto__都会打印true,而缺少支持的浏览器__proto__会打印false.检查兼容性列表很明显,IE <11将评估表达式false.因此,您将无法instanceof d3.selection用于检查IE <11中的D3选择.这是D3 的已知问题,但它已关闭,无法修复.

分析

来自D3的github存储库:

  1. selection/selection.js

查看其定义d3.select()是您通话的切入点:

d3.select = function(node) {
  // ... removed for brevity

  return d3_selection([group]);
};
Run Code Online (Sandbox Code Playgroud)

这最终将返回调用的结果,而调用的结果d3_selection()又是子类d3_selectionPrototype = d3.selection.prototype.

function d3_selection(groups) {
  d3_subclass(groups, d3_selectionPrototype);
  return groups;
}
Run Code Online (Sandbox Code Playgroud)
  1. 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];
};
Run Code Online (Sandbox Code Playgroud)

Object.prototype.__proto__通过检查__proto__空对象上是否存在访问者属性来检查浏览器是否支持{}.如果浏览器支持它,D3将直接分配原型,从而使其成为实例d3.selection.否则,原型的所有属性将被复制到要返回的对象,而不会明确地设置原型.在这种情况下,您的表达式将评估为false.

解决方法

因为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
Run Code Online (Sandbox Code Playgroud)