-1

I'm using an example from here.

    function Restaurant() {
        this.mongoose = 'beans';
        this.freedom = {bear: 'love', a: 12};
    
        var myPrivateVar;
    
        // Only visible inside Restaurant()
        var private_stuff = function() {
            myPrivateVar = "I can set this here!";
            this.mongoose = 12;
            this.freedom.a = 14; // <= 'a' undefined 2nd time
        }

        // use_restroom is visible to all    
        this.use_restroom = function() {
            private_stuff();
        }

        // buy_food is visible to all    
        this.buy_food = function() {
            private_stuff();
        }
    
        private_stuff.call(this);
    }
    
    var bobbys = new Restaurant();
    bobbys.buy_food() // <= fails

I set this.freedom.a to 14 in private_stuff() and then I call bobbys.buy_food(). When that function is called, this.freedom apparently is undefined, so I can't set a.

Does anybody know why it fails on freedom and not on mongoose?

I appreciate comments, but if someone posts an 'Answer', then I can close this as solved, and give you the credit.

  • `this` is in `private_stuff` is not what you might expect. Use an arrow function to bind correct `this` in a nested function. – Teemu May 05 '21 at 16:01
  • 1
    See [How to access the correct `this` inside a callback?](https://stackoverflow.com/q/20279484) and [How does the “this” keyword work?](https://stackoverflow.com/q/3127429) although in your case I don't even know why you use `this`. The structure of this code is just weird. – VLAZ May 05 '21 at 16:01
  • Look at the post date. _Ten years_ is a lot of time. Nobody writes javascript like this anymore. – georg May 05 '21 at 16:02
  • Hi @VLAZ. Weird? Maybe. How would you use use the instance variables, if you were not using `this`? –  May 05 '21 at 16:03
  • 1
    One of the advantages of using the Revealing Module Pattern (which is what I think this is) is to not have to use `this`. Why not just remove it, and return an object with the public methods/properties? – evolutionxbox May 05 '21 at 16:03
  • What is the output supposed to be? None of the functions return anything? – evolutionxbox May 05 '21 at 16:08
  • 1
    @AqC depends on what you want to do with those variables. Does it even make sense to have instance variables? You could just convert them to local variables. But in general, it's just trying to fit a square peg in a round hole - this code is just awkward. Using the class syntax is probably an improvement. – VLAZ May 05 '21 at 16:08
  • 1
    @VLAZ the fact RMP uses closures puts it above classes for me. No need to mess with `this` at all. – evolutionxbox May 05 '21 at 16:09
  • 1
    @evolutionxbox don't know what RMP is. But the main concern should be what interface you want to expose to consumers. I don't know what that would be for OP, so I cannot really say what the most appropriate thing would be. Class syntax is just fairly easy to work with and can work for many purposes if it's supposed to be OO-related. – VLAZ May 05 '21 at 16:15
  • 1
    @VLAZ RMP is [Revealing Module Pattern](http://jargon.js.org/_glossary/REVEALING_MODULE_PATTERN.md) a pattern which pre-dates classes. Simpler than classes, and more flexible (for now). – evolutionxbox May 05 '21 at 16:17
  • Thank you for the very helpful discussion. I really appreciate it. Incidentally, I didn't know what RMP was either. I find it hard to ask a question if I don't know the name of something. –  May 05 '21 at 16:21
  • @evolutionxbox, yeah - this was just an example to play with, demonstrate from, and see how `this` works. (For a bigger real project.) But now I know I shouldn't be using `this` anymore anyway. Thank you for saving me from future embarrassment! –  May 05 '21 at 16:26

3 Answers3

2

If you're interested in using this pattern correctly, its whole point is to avoid this (let alone .call(this)) altogether. Your "private" methods and properties are just variables in a closure, and public methods/props are attached to a local object, which is either a closed this or simply a literal:

function Restaurant() {
    var self = this;  // or {}

    self.publicProp = '';

    var privateProp = '';

    var privateFunc = function() {
        privateProp = 'hello';
        self.publicProp = 'world';
    }

    self.publicFunc = function() {
        privateFunc();
        return privateProp;
    }
    
    // return self; // if used a literal above
}

var bobbys = new Restaurant();
console.log(bobbys.publicFunc())
console.log(bobbys.publicProp)
georg
  • 211,518
  • 52
  • 313
  • 390
  • This is the only good answer here that offers an explanation... I'm so confused how the others have upvotes – Martin May 05 '21 at 16:35
  • @Martin: in the todays like-oriented culture, upvotes are not really related to the content. – georg May 05 '21 at 16:43
0

    function Restaurant() {
        var ths = this;
        this.mongoose = 'beans';
        this.freedom = {bear: 'love', a: 12};
    
        var myPrivateVar;
    
        // Only visible inside Restaurant()
        var private_stuff = function() {
            myPrivateVar = "I can set this here!";
            this.mongoose = 12;
            ths.freedom.a = 14; // <= 'a' undefined 2nd time
        }

        // use_restroom is visible to all    
        this.use_restroom = function() {
            private_stuff();
        }

        // buy_food is visible to all    
        this.buy_food = function() {
            private_stuff();
        }
    
        private_stuff.call(this);
    }
    
    var bobbys = new Restaurant();
    bobbys.buy_food()

Try this

georg
  • 211,518
  • 52
  • 313
  • 390
Amr
  • 9
  • 6
0

Now it should work :)

just use call in your buy food method.

function Restaurant() {
    this.mongoose = 'beans';
    this.freedom = {bear: 'love', a: 12};

    var myPrivateVar;

    // Only visible inside Restaurant()
    var private_stuff = function() {
        myPrivateVar = "I can set this here!";
        this.mongoose = 12;
        this.freedom.bear = 14; // <= 'a' undefined 2nd time
    }

    // use_restroom is visible to all    
    this.use_restroom = function() {
        private_stuff();
    }

    // buy_food is visible to all    
    this.buy_food = function(...args) {
        private_stuff.call(this, ...args);
    }

    private_stuff.call(this);
}

var bobbys = new Restaurant();
bobbys.buy_food()
Robert
  • 2,538
  • 1
  • 9
  • 17
  • Perhaps explain, for future visitors, what you did and why that fixed it? – Martin May 05 '21 at 16:20
  • Function private_stuff() in buy_food during phase of creation don't bind this to it's clousre. It is just pure private_stuff function, so 'this' can't refer to Restaurant. Other solution is create private stuff_b.bind(this) and call it in buy_food. – Robert May 05 '21 at 17:39
  • PS. Js have camelCase method name convention not snake_case. I know python habits but just for formals. – Robert May 05 '21 at 17:42