简体   繁体   中英

Phonegap localstorage and object-oriented JS

I have the following method:

DBConnection.prototype.successHandler = function(){
  console.log("DB_INFO: Schema created");
  for (k in this) console.log(k);
  this.setStatus(DB_STATUS_OK);
}

I call this in a transaction like this:

DBConnection.prototype.createSchema = function(){
  try {
    this.c2db.transaction(
      function(tx){
        tx.executeSql('CREATE TABLE IF NOT EXISTS person(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL DEFAULT "");',
        [], this.nullDataHandler, this.errorHandler);
        tx.executeSql("INSERT INTO person(id, name) VALUES (NULL, 'miloud');",
          [], this.nullDataHandler, this.errorHandler);
      },
      this.errorHandler,
      this.successHandler
    );
  } catch(e){
    console.log("DB_ERROR: error during insert with message: " + e);
    return;
  }
}

The problem is that I get: Uncaught TypeError: Object [object Window] has no method 'setStatus' which is clearly telling that what I am accessing is not the DBConnection instance that I am using when I am in the success callback. How come? What is this refering to inside this callback? Is there a way to overcome this problem?

EDIT

Callbacks are defined as:

DBConnection.prototype.errorHandler = function(errorMsg){
  console.log("DB_ERROR: error creating schema with msg " + errorMsg.message);
}
DBConnection.prototype.successHandler = function(){
  console.log("DB_INFO: Schema created");
  for (k in this) console.log(k);
  this.setStatus(DB_STATUS_OK);
}

And setStatus method as

DBConnection.prototype.setStatus = function(str_status){
  localStorage.setItem(db_name, str_status);
}

Thanks!

This occurs because this within a javascript function refers to the object that preceded it in a dot notation when called. But functions in javascript are first-class values and can be called outside of objects (or indeed, for totally different objects). For example, if obj is an object:

obj.myFunc = function() { console.log(this) };
obj.myFunc(); // <- Here this === obj
var freeFunc = obj.myFunc; // The function is just a value, we can pass it around
freeFunc(); // <- Now this === the top object (normally window)
            // Still the same function, but *how* it was called matters

What you are doing is passing the function referred to by this.successHandler into the transaction call, but the function doesn't know anything about the object you took it from. When it is called by transaction it is executed without an object and this just becomes window .

To solve this you can use the fact that javascript has closures and wrap the function with another anonymous function:

DBConnection.prototype.createSchema = function(){
  try {

    var that = this;

    this.c2db.transaction(
      function(tx){
        tx.executeSql('CREATE TABLE IF NOT EXISTS person(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL DEFAULT "");',
        [], this.nullDataHandler, this.errorHandler);
        tx.executeSql("INSERT INTO person(id, name) VALUES (NULL, 'miloud');",
          [], this.nullDataHandler, this.errorHandler);
      },
      this.errorHandler,
      function() { that.successHandler(); }
    );
  } catch(e){
    console.log("DB_ERROR: error during insert with message: " + e);
    return;
  }
}

Now successHandler will be called with that as this , which is the same as the original this .

This is a common misconception about this but there are also lots of explanations online, just google "javascript this".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM