0

This is my first attempt to javascript prototyping. I am using the Espruino(javascript interpreter for microcontrollers) to get data from environment sensors. I am trying to pause my code for 1000ms, then execute the getSensorReading() method which is(I think) located inside of another method. How do I execute getSensorReading() method? I believe the error is cause by this:

setTimeout(function (e) { this.getSensorReading(); }, w); //Attempting to execute getSensorReading()

I am receiving this error:

Uncaught Error: Function "getSensorReading" not found!  at line 1 col 8 { this.getSensorReading(); }
        ^ in function called from system

Code:

I2C1.setup({scl:b6, sda:b7});

function Sensor (theType, theAddress) {
  this.type = theType;   //i.e. PH
  this.address = theAddress;  //i2c Address
  this.sensorResult = 0; //Store sensor result
  this.cmdTable = {
    "Calibrate" : {  //List of Calibration commands and timeout value.
      "clear" : { "cmd" : "Cal,Clear",      "wait" : 300  },
      "mid"   : { "cmd" : "Cal,mid,7.00",   "wait" : 1300 },
      "low"   : { "cmd" : "Cal,low,4.00",   "wait" : 1300 },
      "high"  : { "cmd" : "Cal,high,10.00", "wait" : 1300 },
      "query" : { "cmd" : "Cal,?",          "wait" : 300  }
    },
    "Information" : {  //Device Information

    },
    "LED" : {  //Enable / Disable or Query the LEDs
      "L0" : { "cmd" : "L,0", "wait" : 300 },
      "L1" : { "cmd" : "L,1", "wait" : 300 },
      "L?" : { "cmd" : "L,?", "wait" : 300 }
    },
    "Reading" : {  //Takes a single reading
      "R" : { "cmd" : "R,25.6", "wait" : 1000 } //Takes a single temperature compensated reading
    },
    "Serial"      : {  //Switch back to UART mode

    },
    "Sleep"       : {  //Enter low power sleep mode

    },
    "Status"      : {  //Retrieve status information

    },
    "Temperature" : {  //Set or Query the temperature compensation
      "T"  : { "cmd" : "T,19.5", "wait" : 300 },  //Where the temperature is any value; floating point, or int, in ASCII form
      "T?" : { "cmd" : "T,?",   "wait" : 300 }  //Query the set temerature
    },
    "Factory"     : {  //Factory reset

    },
  };
}

Sensor.prototype = {
  constructor: Sensor,
  getSensorType:function () {
    return this.type; //Get Sensor type
  },
  getSensorAddress:function () {
    return this.address; //Get Sensor address
  },
  getSensorReading:function() {
    a = this.getSensorAddress;
    console.log("i2c Address: " + a);
    //d = I2C1.readFrom(a, 7);
    return d;
  },
  getSensorResult:function () {
    a = this.getSensorAddress;
    c = this.cmdTable.Reading.R.cmd;
    w = this.cmdTable.Reading.R.wait;

    //I2C1.writeTo(a, c);
    setTimeout(function (e) { this.getSensorReading(); }, w); //Attempting to execute getSensorReading()
  },
  storeSensorResult:function () {

  },
  updateResTemp:function (temp) {
    console.log("Before: " + this.cmdTable.Reading.R.cmd);
    this.cmdTable.Reading.R.cmd = "R," + temp;
    console.log("After: " + this.cmdTable.Reading.R.cmd);
  }
};

var ph = new Sensor("ph", 0x63);

ph.updateResTemp(90.5);
ph.getSensorResult();
dottedquad
  • 1,371
  • 6
  • 24
  • 55
  • 3
    Look into [how `this` works](http://stackoverflow.com/questions/3127429/javascript-this-keyword) and `Function.prototype.bind`. Also, you forgot to declare all your local variables; you need to use `var`. – elclanrs Nov 19 '14 at 05:10

3 Answers3

2

In your code "this" in setTimeout callback refers the parent function getSensorResult. That function doesn't have a function called getSensorReading. That's the reason for the error... Also as you are using global variables inside function unexpected results may occur by overbidding the variables. Make them global with var keyword. Try changing like this..

getSensorReading:function() {
    var a = this.getSensorAddress;
    console.log("i2c Address: " + a);
    //var d = I2C1.readFrom(a, 7);
    return d;
  },
getSensorResult:function () {
    var a = this.getSensorAddress;
    var c = this.cmdTable.Reading.R.cmd;
    var w = this.cmdTable.Reading.R.wait;
    var that = this;
    //I2C1.writeTo(a, c);
    setTimeout(function (e) { that.getSensorReading(); }, w); //Attempting to execute getSensorReading()
  }
Sampath Liyanage
  • 4,776
  • 2
  • 28
  • 40
  • SO I can better understand this. The reason why var that = this works is because this points to the parent: Sensor.prototype allowing me to call getSensorReading? – dottedquad Nov 19 '14 at 06:28
  • 1
    "this" in "that = this" points to the object "ph" not to the Sensor.prototype. "that" is a global variable to the function "ph.getSensorResult". Because of that you can access the parent of "ph.getSensorResult" with "that". – Sampath Liyanage Nov 19 '14 at 06:44
1

Declare global method foo and sub-method bar and refer to sub-method as function in itself, you can use this keyword inside sub-method by addressing previously declared variable, and then declare the return variable as the sub-method process.

Foo: function()
{
    var a='a';
    var ret='b';

    var Bar = function()
    {
        this.a='a';
        return 'a';    
    }

    ret=Bar();

    return ret; 
}
sysenter
  • 75
  • 1
  • 9
0

Agreed with looking into this, Function.prototype.bind, and also the prototype chain in general. Also, javascript is a dynamically bound language. You can re-bind this.

you can either store a reference to this as a closure variable, or bind the function literal that you're passing to setTimeout to the context you want (Sensor.prototype or this in that context)

EDIT: In lieu of having bind available, you can accomplish the same thing with apply, call, or closures.

getSensorResult:function () {
    a = this.getSensorAddress;
    c = this.cmdTable.Reading.R.cmd;
    w = this.cmdTable.Reading.R.wait;

    //I2C1.writeTo(a, c);
    setTimeout((function(_this) {
      return function (e) {
        _this.getSensorReading();
      }
    })(this), w); //Attempting to execute getSensorReading()
}
Evil Buck
  • 1,068
  • 7
  • 20
  • I researched .bind(this) and found out that .bind is not supported by Espruino; however, the developer stated that it is on his to do list. – dottedquad Nov 19 '14 at 21:13