How to access correct "this" in callback
P粉296080076
P粉296080076 2023-10-11 09:42:02
0
2
576

I have a constructor that registers an 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 as
var obj = new MyConstructor('foo', transport);


However, I cannot access the data property of the object created within the callback. It looks like this does not refer to the created object, but to another object.

I also tried using object methods instead of anonymous functions:

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', this.alert);
}

MyConstructor.prototype.alert = function() {
    alert(this.name);
};

But it also has the same problem.

How to access the correct object?

P粉296080076
P粉296080076

reply all(2)
P粉311423594

The following are several ways to access the parent context in the child context - H2>
  1. You can use to bind the a>() function.
  2. Store a reference to context/this in another variable (see example below).
  3. Use ES6 arrow functionality.
  4. Change code, functional design and architecture - for this you should master Design Patterns a> in JavaScript.

1.Use bind()function

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', ( function () {
        alert(this.data);
    }).bind(this) );
}
// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};
// called as
var obj = new MyConstructor('foo', transport);

If you are using Underscore.js - http://underscorejs.org/#bind

transport.on('data', _.bind(function () {
    alert(this.data);
}, this));

2. Store a reference to context/this in another variable

function MyConstructor(data, transport) {
  var self = this;
  this.data = data;
  transport.on('data', function() {
    alert(self.data);
  });
}

3.Arrow function

function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}
P粉968008175

AboutWhat you should know about this

this (aka "context") is a special keyword within each function whose value depends only on how the function is called, not how/when/what Where it is called it is defined. It is not affected by lexical scope like other variables (except arrow functions, see below). Here are some examples:

function foo() {
    console.log(this);
}

// normal function call
foo(); // `this` will refer to `window`

// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`

// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`

To learn more about this , please view the MDN documentation .


How to quote the correct this

Use arrow functions

ECMAScript 6 introduces arrow functions, which can be thought of as lambda functions. They do not have their own this binding. Instead, this is looked up in scope just like a normal variable. This means you don't have to call .bind. This isn't their only special behavior, see the MDN documentation for more information.

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', () => alert(this.data));
}

Don’t use this

You don't actually want to access this specifically, but access the object it refers to. That's why a simple solution is to simply create a new variable that also references the object. Variables can have any name, but common ones are self and that.

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function() {
        alert(self.data);
    });
}

Since self is a normal variable, it follows lexical scoping rules and can be accessed inside the callback. This also has the advantage that you can access the this value of the callback itself.

Explicitly setting the callback's this - Part 1

It may seem like you have no control over the value of this since its value is set automatically, but that's not actually the case.

Every function has method .bind [docs], which returns a new function where this Bind to a value. This function has exactly the same behavior as the function you call .bind, except that this is set by you. No matter when or how the function is called, this will always refer to the passed value.

function MyConstructor(data, transport) {
    this.data = data;
    var boundFunction = (function() { // parenthesis are not necessary
        alert(this.data);             // but might improve readability
    }).bind(this); // 

In this example, we bind the callback's this to the value of this of MyConstructor.

Note: When binding the context of jQuery, use jQuery .proxy [docs] replace. The reason for this is so that you don't need to store a reference to the function when unbinding the event callback. jQuery handles this internally.

Setting the callback this - Part 2

Some functions/methods that accept callbacks also accept a value that the callback's this should reference. This is basically the same as binding it yourself, but the function/method does it for you. Array#map [docs]This is the method. Its signature is:

array.map(callback[, thisArg])

The first parameter is the callback, and the second parameter is the value that this should reference. Here is a contrived example:

var arr = [1, 2, 3];
var obj = {multiplier: 42};

var new_arr = arr.map(function(v) {
    return v * this.multiplier;
}, obj); // 

Note: Whether it is possible to pass a value for this is usually mentioned in the documentation for that function/method. For example, jQuery's $.ajax method [docs] describes an option called context:


FAQ: Using Object Methods as Callbacks/Event Handlers

Another common manifestation of this problem is when an object method is used as a callback/event handler. Functions are first-class citizens in JavaScript, and the term "method" is just a colloquial term for a function, which is the value of an object's property. But the function doesn't have a specific link to its "containing" object.

Consider the following example:

function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = function() {
    console.log(this.data);
};

Function this.method is specified as the click event handler, but if document.body is clicked, the logged value will be undefined because in In the event handler, this refers to document.body, not the instance of Foo.
As already mentioned at the beginning, what this refers to depends on how the function is called, not how it is defined. It might be more obvious that the function has no implicit reference to the object if the code looks like this:

function method() {
    console.log(this.data);
}


function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = method;

Solution

Same as mentioned above: use .bind to explicitly bind this to a specific value if available

document.body.onclick = this.method.bind(this);
Or explicitly call the function as a "method" of the object by using an anonymous function as a callback/event handler and assigning the object (

this

) to another variable:

var self = this;
document.body.onclick = function() {
    self.method();
};
Or use arrow functions:

document.body.onclick = () => this.method();
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template