Tuesday, 15 March 2011

javascript - How to access the correct `this` / context inside a callback? -



javascript - How to access the correct `this` / context inside a callback? -

i have constructor function registers event handler:

class="snippet-code-js lang-js prettyprint-override">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 within callback. looks this not refer object created other one.

i tried utilize 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 right object?

what should know this

this (aka "the context") special keyword within 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 phone 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 larn more this, have @ mdn documentation.

how refer right this don't utilize 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, mutual 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 within callback. has advantage can access this value of callback itself.

explicitly set this of callback - part 1

it might have no command 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, utilize jquery.proxy [docs] instead. reason don't need store reference function when unbinding event callback. jquery handles internally.

ecmascript 6: utilize 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 phone 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 take callbacks take 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 , sec 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) { homecoming v * this.multiplier; }, obj); // <- here passing `obj` sec argument

note: whether or not can pass value this mentioned in documentation of function/method. example, jquery's $.ajax method [docs] describes alternative called context:

this object made context of ajax-related callbacks.

common problem: using object methods callbacks / event handlers

another mutual 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 next 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 within 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, utilize .bind explicitly bind this specific value

document.body.onclick = this.method.bind(this);

or explicitly phone 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 utilize arrow function:

document.body.onclick = () => this.method();

javascript callback this

No comments:

Post a Comment