The problem with the function scope object

Posted on
  • There is an object created via new:

    function class_1()
    {
    this.A_1;
    this.B_1;
    }
    
    class_1.prototype.func_class_1 = function()
    {
    	/*
    		here are some actions with variables this.A_1, this.B_1
    	*/
    }
    
    function class_2 (_obj /*object of type class_1*/)
    {
    this.A_2;
    this.B_2;
    this.Obj_2 = _obj;
    }
    
    class_2.prototype.func_class_2  = function()
    {
    	//function call problem !!!
    	this.Obj_2.func_class_1();
    }
    
    var o1 = new class_1();
    var o2 = new class_2(o1);
    
    o2.func_class_2(); //Uncaught Error: Field or method "func_class_1()" does not already exist, and can't create it on undefined
    
    

    Help !
    I tried various options with this, call and bind, nothing helped. How to organize a call to "this.Obj_2.func_Class_1()" ?

  • Which firmware version are you running this on, and on what device?

    I just ran this on the latest builds and it works fine.

    However: If you put this in the right-hand side of the web IDE you get loads of errors. I'd fix those first.

    Specifically what do you intend to do with this.A_1;/etc? You're just referencing fields that don't exist yet, without setting them to anything.

  • Thank you for such a quick response !
    I use the cost of production of Amperka (http://amperka.ru/) - "IskraJS" based on Espruino 1v92.194

  • In the code there are no syntax errors it builds and runs fine, below part of code:

    function TObj_1(_pin)
    {	
    	/*** константы класса ***/
    	this.MinPulse = 453.0; //минимальная длительность импульса которая соответствует крайнему "меньшему" положения ротора
    	this.MaxPulse = 2050.0; //макисмальная длительность импульса которая соответствует крайнему "меньшему" положения ротора
    	this.Ks = 8.7; //коэффициент преобразования в ф-ции Y=kA+B (линейная кривая самого сервопривода
    		
    	/*** поля класса ***/
    	this.Pin = null; //пин микропроцессора на котором "сидит" сервопривод
    	this.Value = 0.0; //конечное значение яркости свечения
    	this.CurValue = 0.0; //текущее значение яркости свечения
    	this.Speed = 0.0; //текущая скорость процесса
    
    	this.Pin = _pin; //задать пин к которому привязан сервопривод
    }
    TObj_1.prototype.BunRunAnimation = function()
    {
    	this.FlagBunAnimation = true; //запретить "ручной" запуск Animation(...)
    		this.StopAnimation(); //остановить текущую анимацию
    };
    
    function TObj_2(_tobj_1)
    {
    	this.PHASE_ARR = [ "START_MOVE", "START_WAIT", "DOWN_MOVE", "DOWN_WAIT", "UP_MOVE", "UP_WAIT" ];
    	
    	this.ANGLE_START = 30; //конечный угол ротора фазы START_MOVE
    	this.ANGLE_UP = 20; //конечный угол ротора фазы UP_MOVE
    	this.ANGLE_DOWN = 0; //конечный угол ротора фазы DOWN_MOVE
    	
    	this.TIME_START = 15; //время нахождения в позиции START_WAIT, секунд
    	this.TIME_UP = 0.5;  //время нахождения в позиции UP_MOVE, секунд
    	this.TIME_DOWN = 0.7;  //время нахождения в позиции UP_WAIT, секунд
    		
    	this.SPEED_START = 25; //скорось движения ротора в фазе START_MOVE, %/s
    	this.SPEED_UP = 40;  //скорось движения ротора в фазе UP_MOVE, %/s
    	this.SPEED_DOWN = 25;  //скорось движения ротора в фазе DOWN_MOVE, %/s
    	
    	this.INTERVAL_PLAY = 60.0; //определяет период в ms запуска внутренней ф-и setTimeout
    	
    
    	this.Obj1 = _tobj_1; //инициируем поле объектом класса Servo
    };
    TObj_2.prototype.TaskRun = function()
    {
    	let _this = this;
    	
    	if( !_this.FlagTaskRun )
    		{
    			_this.FlagTaskRun = true; 
    				_this.Obj1.BunRunAnimation(); //Error !
    			
    			_this.CurPhase = _this.PHASE_ARR[0]; 
    		}
    		
    	switch(_this.CurPhase)
    	{
    		case "START_MOVE":
    							if( !_this.FlagSTART_MOVE )
    							{
    								_this.Obj1.AnimationTask(_this.ANGLE_STA­RT, _this.SPEED_START);
    									_this.FlagSTART_MOVE = true;
    							}
    							else
    							{
    								if ( !_this.Obj1.GetStatusRunAnimation() ) //Error !
    								{
    									_this.CurPhase = _this.PHASE_ARR[1]; 
    										_this.FlagSTART_MOVE = false; 
    								}
    							}
    							
    			break;
    };
    
  • Moving this to 'other boards' - IskraJS isn't an official board - they're just using the Open Source Espruino firmware.

    I've tried to run your code even on a 1v92 version of Espruino and it works (without the Exception) - perhaps you could contact Amperka to see if they can help you out.

  • Thanks again !
    Already sent a request to Amperka

  • The problem is solved. Loss of context occurred in one of the plugins. The firmware of the Amperka code executes correctly.

  • Great! By 'loss of context', you mean you called it in a setTimeout or something?

  • Yes, "this" was lost in one of setTimeout

  • JavaScript provides you with standard means to ensure the desired context:

    • You can pass parameter for the function in

      setTimeout(function(_, otherParms,...){
      _.memberOfContextObject;
      _.memberOfContextObject();
      }, timeoutTimeInMS, contextObject, otherParms,...);
      
    • Alternative is to bind the function and then pass to `

      setTimeout(function(otherParms,...){
      this.memberOfContextObject;
      this.memberOfContextObject();
      }.bind(contextObject), timeoutTimeInMS, otherParms,...);
      
    • This works too, but is not as flexible as above options:

      function anyFunctionOfThis() {
      var _this = this; // create non-this reference of this
      setTimeout(function(otherParms,...){
        _this.memberOfContextObject;
        _this.memberOfContextObject();
      }, timeoutTimeInMS, otherParms,...);
      

    As you know, you can defined the function as a named function outside of setTimeout(... or setInterval(... or ..., functionAsCallbackParm,...either as function or 'method of an object' (see object-oriented programming with JS). I use this when I have to provide them as callbacks in multiple places:

    var fun      = function(otherParms,...) { ... };
    var funBound = fun.bind(contextObject);
    
    setTimeout(funBound, timoutTimeInMS, otherParms,...
    

    There are many options and combinations there of you can chose from for the optimal use in your situation.

    For the alternative 'this', I use the _this or short form of it _ to indicate that it is about the this / context object. I've also seen that to be used. But I prefer a more eye catching - and short - form, therefore: _ is my choice.

  • Or.. if the contextObject you need is the outer scope just use a arrow function as setTimeout callback and be done with it.

    Other public choices for the this alter ego are me and self :D

  • Thank you all for the advice !

    function myclassA()
    {
    	this.A = 1;
    	this.TimerID = null;
    }
    
    myclassA.prototype.func_1 = function()
    {
    	/* here some code */
    	this.TimerID = setInterval(this.func_2.bind(this), 50);
    }
    
    myclassA.prototype.func_2 = function()
    {
    	/* There was an error ! )) */
    }
    
    function myclassB(_object)
    {
    	this.B = 1;
    	this.Obj = _object;
    }
    
    myclassB.prototype.func_1 = function()
    {
    	/* here some code */
    	this.Obj.func_1();
    }
    
    
  • ...?

    ...do not exactly get what above code should proof or disproof...

    (function(){
    var MyClassA = function(name, checkInInterval)
      {
        this.name = name;
        this.checkInInterval = checkInInterval;
        this.TimerID = null;
        this.commander = null;
      }
    MyClassA.prototype.func_1 = function(commander)
      {
        /* here some code */
        this.commander = commander;
        this.TimerID = setInterval(this.func_2.bind(this), this.checkInInterval);
      }
    MyClassA.prototype.func_2 = function()
      {
        var time = (typeof getTime != "undefined") ? getTime() : new Date().getTime();
        console.log(Math.floor(time)
           + ": Hi, my name is " + this.name
           + "; " + this.commander.name
           + " commanded me to check in"
           + " every " + (this.checkInInterval / 1000)
           + " seconds. --- Bye!");
      }
    
    var MyClassB = function(name, _object)
      {
        this.name = name;
        this.Obj = _object;
      }
    MyClassB.prototype.func_1 = function()
      {
        /* here some code */
        this.Obj.func_1(this);
      }
    
    var objAlf, objAnn, objBen, objBob;
    
    var onInit = function()
      {
        objAlf = new MyClassA("Alf",2000);
        objAnn = new MyClassA("Ann",5000);
        objBen = new MyClassB("Ben",objAlf);
        objBob = new MyClassB("Bob",objAnn);
        objBen.func_1();
        objBob.func_1();
      }
      
    setTimeout(onInit, 1000);
    })()
    

    Should run in Espruino and provide output in the console like that:

    1513144683321: Hi, my name is Alf; Ben commanded me to check in every 2 seconds. --- Bye!
    1513144685319: Hi, my name is Alf; Ben commanded me to check in every 2 seconds. --- Bye!
    1513144686318: Hi, my name is Ann; Bob commanded me to check in every 5 seconds. --- Bye!
    1513144687321: Hi, my name is Alf; Ben commanded me to check in every 2 seconds. --- Bye!
    1513144689322: Hi, my name is Alf; Ben commanded me to check in every 2 seconds. --- Bye!
    1513144691320: Hi, my name is Alf; Ben commanded me to check in every 2 seconds. --- Bye!
    1513144691321: Hi, my name is Ann; Bob commanded me to check in every 5 seconds. --- Bye!
    1513144693321: Hi, my name is Alf; Ben commanded me to check in every 2 seconds. --- Bye!
    1513144695319: Hi, my name is Alf; Ben commanded me to check in every 2 seconds. --- Bye!
    1513144696318: Hi, my name is Ann; Bob commanded me to check in every 5 seconds. --- Bye!
    

    ...you can also just open the debugger of (chrome) browser (with 'right-click' Inspect) and paste the code into the console... :)

    As the output shows, Alf - objAlf - and Ann - objAnn- know still about their names, their time interval to show up, and who commanded them: Ben and Bob.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

The problem with the function scope object

Posted by Avatar for Konkery @Konkery

Actions