• Mon 2018.09.17

    ref MDN bind(): https://developer.mozilla.org/en-US/docs­/Web/JavaScript/Reference/Global_Objects­/Function/bind

    Goal:
    1) Retrieve the internal contents of an instantiated class
    2) Modify the internal value and retain through subsequent retrieval attempts

    The MDN example works using the Json object notation form. When I attempt to use a class however, I'm greeted with either function not found or undefined

    class TestBind {
    
      constructor() {
    //    var vX = -1;
        var vX = 23;
      }
     
      getX() { 
        return this.vX; 
      }
    
      setX( obj ) {
        this.vX = obj;
      }
    
    }
    exports = TestBind;
    


    The constructor seems to ignore the initial default assignment - why not -1

    var tb = new TestBind();
    var g = tb.getX;
    print g
    
    Undefined
    


    Then if I use a setter, then it's not clear if the constructor initialized correctly

    var tb = new TestBind();
    tb.setX = 42;
    var g = tb.getX;
    print g
    
    =42
    



    If I use the () notation - so which is correct, without the () or using the () ?
    How can function getX() not be found when it is clearly defined?

    var tb = new TestBind();
    var g = tb.getX();
    print g
    
    Uncaught Error: Function "getX" not found!
    


    Following the example from MDN, and applying to this class

    var tb = new TestBind();
    //tb.setX = 42;
    //var g = tb.getX;
    var g = tb.getX();
    print g
    var bg = g.bind(tb);
    print bg
    
    var bg = g.bind(tb);
    Uncaught Error: Cannot read property 'bind' of undefined
    



    VERSION 1v99


    1 Attachment

  • The intended use is:

    // class def
    function TestBind(x) {
      this.x = x;
    }
    TestBind.prototype.getX = function() {
      console.log('TestBind.getX(): returning ' + this.x);
      return this.x;
    }
    
    // usage to create an object instance bound method as function
    var tb = new TestBind(42);
    var gX = tb.getX;
    var bgX = gX.bind(tb);
    // var bgX = tb.getX.bind(tb); 
    

    ...use of the bound method can now be used as plain function in all places where only a function can be passed:

    • setInterval()
    • setTimeout()
    • callback

    in a simplified and fast form:

    setInterval(bgX,1500);
    

    in replacement of anonymous function:

    setInterval(function(){
        tb.gX();
    },1500);
    

    Bind is nothing else than the above, just a bit faster, smarter, and leaner (less resources).

    Often, you will see the pattern of a var _this = this; or var _ = this; in a method to refere to the current object and then the use of if in a 'closures'. Becausethis is runtime executed in the context at that very (future) moment, this as on setup is then not available anymore (or different), and with above approach one makes clear that it mans the current instance. For example with the your example above:

    TestBind.prototype.getX = function() {
      var _this = this;
      setTimeout(function(){
        console.log('.getX(): for TestBind with x=' + _this.x + ' was accessed 10 seconds ago');
      },10000);
      return this.x;
    }
    

    There was a time that this was the only way to be done. But a while now, setTimeout() (and setInterval() ?) allow passing of arguments that are resolved at setup of setTimeout() (and setInterval()?):

    TestBind.prototype.getX = function() {
      setTimeout(function(){
        console.log('.getX(value): for TestBind with x=' + value + ' was accessed 10 seconds ago');
      },10000,this.x);
      return this.x;
    }
    

    Imagine a second method

    TestBind.prototype.doY = function() {
      setTimeout(this.gX.bind(this),5000);
      console.log("...just did Y.");
    }
    

    that will do something in a timeout or interval involving the .getX(), then you can do that with a an anonymous function and 'helper' variable _this or with bind... bind... both work. I do not know the runtime differences and ramification for JS in Espruino vs others...

    .doY() will work on any instance of TestBind instance (or creation). Creating multiples with passing different values for identifying purposes will show that...

    var firstTB = new firstTB(1);
    var secondTB = new firstTB(2);
    firstTB.doY();
    secondTB.doY();
    

    Take also a look at apply(...) and call(...). There are more applications to have a 'function' (or piece / block of - instant - code) as object that is passed around and then then executed. The unbound (undefined object context) or bound (to an object) function is passed around as a reference, and for execution use the regular function argument list parentheses, which is understood as: try to invoke the given thing as a function an passing the the arguments (if there are). You do that all the time with JS programming. The short form of defining functions obfuscates this a bit, but if you use the long way with a variable it becomes obvious... and shows the great Lambda that came to be in the 70'... only Java missed it for so long until recently... so much for progress an new things under the SUN.

    Here some fun to play Math Jeopardy with:

    var  f = function(a) { return a * a; }; // square
    var g = function(a) { return a * a * a; }; // cubic
    
    function j = function(f,x) { // accepts function and a value as args
        console.log("J:  fnct(x) with x = " + x + " returns " + f(x) + ". What is fnct(x) do with x?");
    }
    
    setTimeout(function() {
       j( (Math.random()<0.5) ? f : g, (new Date()).getSeconds() % 6) );
    });
    

    ;-) I added the JS modulo or modulus % with 10 so the numbers stay within 0..9 (or % 6 for 0..5) for players -like me when it it's late - used to pocket calculator or phone only and not anymore to learn square up to 59 and all the tricks that go with it like: 25 square is 2*(2+1) and appended 25... goes for a the one with 5 at the end... 125 square is 12*13 + "25"... Espruino will tell you in the console in an instant... this is for square... so for cubic I should simplify even more... also for me... (it's already late).

    ```

  • I think as usual @allObjects has done an awesome job of answering the question about bind.

    But looking at the code above, there are a few big issues that I thought it might help if I point out in-line:

    class TestBind {
      constructor() {
        var vX = 23;  // This creates a LOCAL VARIABLE - you need this.vX=23;
      }
     
      getX() { 
        return this.vX; 
      }
      setX( obj ) {
        this.vX = obj;
      }
    }
    exports = TestBind; // not really useful in this case as you're using using 'TestBind' directly
    
    var tb = new TestBind();
    var g = tb.getX; // This makes 'g' equal to the function 'getX' itself
    // Check out https://developer.mozilla.org/en-US/docs­/Web/JavaScript/Reference/Functions/get for a real example of getters
    print g // this is not how you call a function in JS. It won't print anything at all. You need print(g)
    
    
    var tb = new TestBind();
    tb.setX = 42; // This just overwrites the 'setX' function with the number 42
    // Check out https://developer.mozilla.org/en-US/docs­/Web/JavaScript/Reference/Functions/set for a real example of setters
    
    var g = tb.getX(); // this works, there is no 'Function "getX" not found!' error so I can only assume you're not uploading the code that you posted
    

    I'm not sure any of these problems you're having would be fixed by how you use bind though.

    I think what you intended to do was probably:

    class TestBind {
      constructor() {
        this.vX = 23;
      }
      getX() {
        return this.vX; 
      }
      setX( obj ) {
        this.vX = obj;
      }
    }
    
    var tb = new TestBind();
    print(tb.getX()); // prints 23
    var g = tb.getX();
    print(g); // prints 23
    tb.setX(42);
    print(tb.getX()); // prints 42
    
  • Tue 2018.09.18

    Thanks both for the quick and attentive responses.

    I thought I'd found the culprit. I mistakenly used tb.setX = 42; when as @Gordon pointed out should use tb.setX(42);

    Note line #6 that shows the class contents aren't getting updated

    But when I run that tb.setX(42);, I'm faced with yet another error:

    >var tb = new TestBind();
    =TestBind: { "vX": 25 }
    =25
    >tb.setX = 42;
    =42
    >print tb.getX();
    =25
    >var bg = g.bind(tb);
    Uncaught Error: Function "bind" not found!
     at line 1 col 12
    var bg = g.bind(tb);
               ^
    >print bg
    =undefined
    >tb.setX(42);
    Uncaught Error: Expecting a function to call, got Number
     at line 1 col 4
    tb.setX(42);
       ^
    >
    

    This is why I originally used the syntax tb.setX = 42; to avoid the 'Expecting a function to call' error

  • ...it looks like hat you have some left-overs in your Espruino...

    g is nowhere defined in that snipped, so I expect it came from previous post... but it also could come from some internal that the interpreter looks at, does not find it a bindable, but thinks it is a number.

    Doing things in the console without wiping every thing out, creates a lot of confusion.

    Again, I feel that Espruino is still playing tricks on you, @Robin... Espruino is a living object,... similar to the DOM of or in a Browser. Most operation on it leave some (big Bear claw) prints behind... to haunt later... Halloween is about to come... So we should get some Espruino driven flashy wearables... what about a contest, @Gordon?

  • could be a nice idea - I'll have a think! I've been meaning to try some contests - for example I reckon now tweets are 280 chars you could do some really interesting things in hardware JS :)

    @Robin as @allObjects says, each command you write on the left-hand side after you upload is changing the state of the interpreter. If you thought that each command you typed was executed on a fresh instance of your code it could actually be a really big cause of the problems you're having.

    Please check out some of the comments below - they might help.

    >var tb = new TestBind();
    =TestBind: { "vX": 25 }
                            <---- was there a command missing here?
    =25
    >tb.setX = 42;          <---- after this, tb.setX is now set to 42. It's no longer
                                  a function
    =42                     
    >print tb.getX();       <---- again, this is NOT how you use print or call a 
                                  function in JS. if you want the console to say 
                                  '=value' just type 'tb.getX()' 
                                  - you don't need 'print'
    =25
    >var bg = g.bind(tb);   <---- as allObjects says - there must be some code here 
                                  you're not posting up as you didn't define 'g' 
                                  previously, but lets assume that code was 
                                  'g = tb.getX()'. 'g' will be 25, so is a number 
                                  and won't have a 'bind' method
    
    Uncaught Error: Function "bind" not found!
     at line 1 col 12
    var bg = g.bind(tb);
               ^
    >print bg               <---- not how you call print, as mentioned above. However 
                                  the code above errored so you wouldn't expect it to 
                                  have written anything to 'bg'
    =undefined
    >tb.setX(42);           <---- If you did this right at the start, it would have 
                                  worked. Since you called it after 'tb.setX = 42', 
                                  'tb.setX' is now 42 so it is not a function you 
                                  can call
    
    Uncaught Error: Expecting a function to call, got Number
     at line 1 col 4
    tb.setX(42);
       ^
    
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Correct syntax needed for bind() on 'this' object using class

Posted by Avatar for Robin @Robin

Actions