javascript - How to access the correct `this` inside a callback? -
i have constructor function registers event handler:
function myconstructor(data, transport) { this.data = data; transport.on('data', function () { alert(this.data); }); } // mock transport object var transport = { on: function(event, callback) { settimeout(callback, 1000); } }; // called var obj = new myconstructor('foo', transport);
however, i'm not able access data
property of created object inside callback. looks this
not refer object created other one.
i tried use object method instead of anonymous function:
function myconstructor(data, transport) { this.data = data; transport.on('data', this.alert); } myconstructor.prototype.alert = function() { alert(this.name); };
but exhibits same problems.
how can access correct object?
what should know this
this
(aka "the context") special keyword inside each function , value depends on how function called, not how/when/where defined. not affected lexical scope, other variables. here examples:
function foo() { console.log(this); } // normal function call foo(); // `this` refer `window` // object method var obj = {bar: foo}; obj.bar(); // `this` refer `obj` // constructor function new foo(); // `this` refer object inherits `foo.prototype`
to learn more this
, have @ mdn documentation.
how refer correct this
don't use this
you don't want access this
in particular, the object refers to. that's why easy solution create new variable refers object. variable can have name, common ones self
, that
.
function myconstructor(data, transport) { this.data = data; var self = this; transport.on('data', function() { alert(self.data); }); }
since self
normal variable, obeys lexical scope rules , accessible inside callback. has advantage can access this
value of callback itself.
explicitly set this
of callback - part 1
it might have no control on value of this
, because value set automatically, not case.
every function has method .bind
[docs], returns new function this
bound value. function has same behavior 1 called .bind
on, this
set you. no matter how or when function called, this
refer passed value.
function myconstructor(data, transport) { this.data = data; var boundfunction = (function() { // parenthesis not necessary alert(this.data); // might improve readability }).bind(this); // <- here calling `.bind()` transport.on('data', boundfunction); }
in case, binding callback's this
value of myconstructor
's this
.
note: when binding context jquery, use jquery.proxy
[docs] instead. reason don't need store reference function when unbinding event callback. jquery handles internally.
ecmascript 6: use arrow functions
ecmascript 6 introduces arrow functions, can thought of lambda functions. don't have own this
binding. instead, this
looked in scope normal variable. means don't have call .bind
. that's not special behavior have, please refer mdn documentation more information.
function myconstructor(data, transport) { this.data = data; transport.on('data', () => alert(this.data)); }
set this
of callback - part 2
some functions/methods accept callbacks accept value callback's this
should refer to. same binding yourself, function/method you. array#map
[docs] such method. signature is:
array.map(callback[, thisarg])
the first argument callback , second argument value this
should refer to. here contrived example:
var arr = [1, 2, 3]; var obj = {multiplier: 42}; var new_arr = arr.map(function(v) { return v * this.multiplier; }, obj); // <- here passing `obj` second argument
note: whether or not can pass value this
mentioned in documentation of function/method. example, jquery's $.ajax
method [docs] describes option called context
:
this object made context of ajax-related callbacks.
common problem: using object methods callbacks / event handlers
another common manifestation of problem when object method used callback / event handler. functions first class citizens in javascript , term "method" colloquial term function value of object property. function doesn't have specific link "containing" object.
consider following example:
function foo() { this.data = 42, document.body.onclick = this.method; } foo.prototype.method = function() { console.log(this.data); };
the function this.method
assigned click event handler, if body clicked, value logged undefined
, because inside event handler, this
refers body, not instance of foo
.
mentioned @ beginning, this
refers depends on how function called, not how defined.
if code following, might more obvious function doesn't have implicit reference object:
function method() { console.log(this.data); } function foo() { this.data = 42, document.body.onclick = this.method; } foo.prototype.method = method;
the solution same mentioned above: if available, use .bind
explicitly bind this
specific value
document.body.onclick = this.method.bind(this);
or explicitly call function "method" of object, using anonymous function has callback / event handler , assign object (this
) variable:
var self = this; document.body.onclick = function() { self.method(); };
or use arrow function:
document.body.onclick = () => this.method();
Comments
Post a Comment