leonormes leonormes -4 years ago 92
Javascript Question

Javascript 'New' object's 'this' in async function

I am working through Marc Wandscheider's 'Learning Node.JS'. I have copied this code for a class and call;

let fs = require('fs');
function FileObject() {
this.filename = '';
this.file_exists = function(callback) {
console.log('About to open: ' + this.filename);
fs.open(this.filename, 'r', function(err, handle) {
if (err) {
console.log('Can\'t open: ' + this.filename);
callback(err);
return;
}
fs.close(handle, function() {});
callback(null, true);
});
};
}
let fo = new FileObject();
fo.filename = 'file_that_does_not_exist';
fo.file_exists((err, results) => {
if (err) {
console.log('\nError opening file: ' + JSON.stringify(err));
return;
}
console.log('file exists!!!');
});


When run it outputs

About to open: file_that_does_not_exist
Can't open: undefined


The undefined is because of the async nature of the
fs.open()
method. The author corrects this by adding a variable to store this in
let self = this;


I would like to use
bind(this);
instead, but cannot work out how to do it! Is there an alternative to using the
self
hack?

Answer Source

The answer to your question is that you can call .bind on the function you pass to fs.open in order to correctly bind this:

fs.open(this.filename, 'r', function (err, handle) {
    if (err) {
        console.log('Can\'t open: ' + this.filename);
        callback(err);
        return;
    }
    fs.close(handle, function() {});
    callback(null, true);
}.bind(this));  // <-- here

An alternative to using self or .bind is to use an arrow function, which provides lexical scoping:

let fs = require('fs');
function FileObject() {
    this.filename = '';
    this.file_exists = function(callback) {
        console.log('About to open: ' + this.filename);
        //                            right here --v
        fs.open(this.filename, 'r', (err, handle) => {
            if (err) {
                console.log('Can\'t open: ' + this.filename);
                callback(err);
                return;
            }
            fs.close(handle, function() {});
            callback(null, true);
        });
    };
}
let fo = new FileObject();
fo.filename = 'file_that_does_not_exist';
fo.file_exists((err, results) => {
    if (err) {
        console.log('\nError opening file: ' + JSON.stringify(err));
        return;
    }
    console.log('file exists!!!');
});

Browser friendly example:

let fs = {
  open: function(filename, type, callback) {
    callback(new Error());
  }
};

function FileObject() {
  this.filename = '';
  this.file_exists = function(callback) {
    console.log('About to open: ' + this.filename);
    //                            right here --v
    fs.open(this.filename, 'r', (err, handle) => {
      if (err) {
        console.log('Can\'t open: ' + this.filename);
        callback(err);
        return;
      }
      fs.close(handle, function() {});
      callback(null, true);
    });
  };
}
let fo = new FileObject();
fo.filename = 'file_that_does_not_exist';
fo.file_exists((err, results) => {
  if (err) {
    console.log('\nError opening file: ' + JSON.stringify(err));
    return;
  }
  console.log('file exists!!!');
});

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download