d3.IElection中的选择类型检查

时间:2015-10-20 09:06:54

标签: d3.js

如何检查给定对象是否为d3选项?

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

console.log(d3.select(document.body) instanceof d3.selection)

1 个答案:

答案 0 :(得分:6)

更新2017-01-17

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

  

选择不再使用prototype chain injection对Array进行子类化;它们现在是普通物体,提高了性能。

API docs明确声明:

  

# d3。选择()<>

     

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

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

d3.select() instanceof d3.selection   // true in Chrome, FF, IE

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

问题

由于D3的内部工作原理,每个支持Object.prototype.__proto__的浏览器都会打印true,而缺少对__proto__的支持的浏览器会打印false。检查compatibility list显而易见的是,IE&lt; 11将表达式评估为false。出于这个原因,您无法使用instanceof d3.selection来检查IE中的D3选择&lt; 11。这是带有D3的known issue,但它已关闭,无法修复。

分析

来自D3&#39;的github存储库:

  1. selection/selection.js
  2. 查看d3.select()的定义,这是您通话的切入点:

    d3.select = function(node) {
      // ... removed for brevity
    
      return d3_selection([group]);
    };
    

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

    function d3_selection(groups) {
      d3_subclass(groups, d3_selectionPrototype);
      return groups;
    }
    
    1. core/subclass.js
    2. 最后,d3.selection的实施提供了问题的答案:

      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

      解决方法

      由于提供了{{3}}作为扩展选择功能的方法,因此您可以通过向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