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
Let's see what this
is defined as for each of your approaches:
// console.log(this) in inline function:
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);
}