d3.select(this) works on mouseover, but not on function called in mouseover

前端 未结 3 1877
感情败类
感情败类 2021-02-05 23:29

I am new to javascript and currently struggling with selecting the this object while trying to do a d3 selection. I\'ve made the following example, with a funct

3条回答
  •  忘了有多久
    2021-02-06 00:11

    Let's see what this is defined as for each of your approaches:

    // console.log(this) in inline function:
     
    
    // console.log(this) in function called from inline function:
    Window → file:///fileName.html
    

    this is set by how a function is called. D3 conveniently sets this to be the DOM element being manipulated by using .apply on the function passed to selection.attr(), selection.on() etc. However, it doesn't do this for functions called within the function passed to selection.attr(), selection.on(), etc.

    We can see that this is indeed the DOM element if we log this in the function passed to selection.on(). If this is not explicitly set, it will be the window (unless using strict mode, then it will be undefined). We can see in the nested function, this is indeed the window.

    Altocumulus's answer and Gerardo's answer avoid the this issue altogether, additionally you could also pass this as some regular argument to the function (this pattern is seen in some examples). But if you want to simply be able to copy and paste the code from the inline function to some separately defined function you can use apply, which will preserve this as the element being modified:

    d3.select("body")
      .append("svg")
      .attr("width", 960)
      .attr("height", 960)
      .on('mousemove', function() {
         var mouse = d3.mouse(this);
         console.log("inline: ", mouse[0]);
         someFunction.apply(this);
    });
    
    function someFunction() {
      var mouse = d3.mouse(this);
      console.log("not inline: ", mouse[0]);
    }

    If you needed to pass parameters to your function along with this, you can still use apply:

    someFunction.apply(this,[parameterA,parameterB,...]);
    function someFunction(parameterA,parameterB) { }
    

    d3.select("body")
      .append("svg")
      .attr("width", 960)
      .attr("height", 960)
      .on('mousemove', function() {
         var mouse = d3.mouse(this);
         console.log("inline: ", mouse[0]);
         someFunction.apply(this,[mouse[0],mouse[1]]);
    });
    
    function someFunction(x,y) {
      var mouse = d3.mouse(this);
      console.log("not inline: ", mouse[0],x,y);
    }

    However, this inline function calling other functions may just be extra work. If you are only calling a function in the inline function, then just pass the called function to selection.on() directly, this preserves this without any extra steps as d3 will apply the expected value to it (it also still gives you access to the datum and index if needed):

    d3.select("body")
      .append("svg")
      .attr("width", 960)
      .attr("height", 960)
      .on('mousemove', someFunction)
    
    function someFunction() {
      var mouse = d3.mouse(this);
      console.log(mouse[0]);
    }

    Don't place the brackets on the function in this case, we don't want to return the result of the function, we want to use the function itself.


    I've use apply (Function.prototype.apply()) in my examples, but you can also use call (Function.prototype.call()), as Altocumulus notes below. The use of call is quite similar. If you aren't passing any parameters to the function and only want to preserve this, the usage is the same: someFunction.apply(this) / someFunction.call(this). But, if passing parameters, call doesn't use an array for the parameters:

    d3.select("body")
      .append("svg")
      .attr("width", 960)
      .attr("height", 960)
      .on('mousemove', function() {
         var mouse = d3.mouse(this);
         someFunction.call(this,mouse[0],mouse[1]); // first parameter will be `this` for someFunction, rest of parameters follow
    });
    
    function someFunction(x,y) {
      var mouse = d3.mouse(this);
      console.log(mouse[0],x,y);
    }

提交回复
热议问题