2

Yes, this question is similar with Inner function cannot access outer functions variable. But it's not the same one. What confused me is "after being changed". Codes below maybe more intuitively.

var serial_maker = function() {
    var prefix = '',
        seq = 0;
    return {
        set_prefix: function(p) {
            prefix = String(p);
        },
        set_seq: function(s) {
            seq = s;
        },
        gensym: function() {
            var result = prefix + seq;
            seq += 1;
            return result;
        }
    };
};
var seqer = serial_maker();
seqer.set_prefix('Q');
seqer.set_seq(1000);
seqer.gensym(); // 'Q1000'

// Rewrite set_seq method
seqer.set_seq = function() {
    seq = 2000;
};
seqer.set_seq();

seqer.gensym(); // 'Q1001', which was expected 'Q2000'

So this is what i want to figure out —— why the rewritten set_seq method didn't change value of the private variable seq in outer function?

Hope i could get some essential answers, thanks =)

Community
  • 1
  • 1
Soon
  • 151
  • 11

4 Answers4

4

You are creating a new closure. The returned function seqer.set_seq is a closure which can access the private variable seq. But the newly defined seqer.set_seq is creating a new closure which cannot access the private variable, instead it creates a new global one window.seq

Try it:

var serial_maker = function() {
    var prefix = '',
        seq = 0;
    return {
        set_prefix: function(p) {
            prefix = String(p);
        },
        set_seq: function(s) {
            seq = s;
        },
        gensym: function() {
            var result = prefix + seq;
            seq += 1;
            return result;
        }
    };
};
var seqer = serial_maker();
seqer.set_prefix('Q');
seqer.set_seq(1000);
seqer.gensym(); // 'Q1000'

// Rewrite set_seq method
seqer.set_seq = function() {
    seq = 2000;
};
seqer.set_seq();

seqer.gensym(); // Q1001 is correct!

console.log(window.seq); // 2000
devnull69
  • 16,402
  • 8
  • 50
  • 61
2

It's actually another seq variable. When you run set_seq for the first time, the seq variable is already bounded to it, it does not read it directly from the function declaration.

In other words, when you define your original function, an object with set_prefix, set_seq and gensym is returned, and each of these function already have a reference to the seq variable, which is defined in the function's closure. When you assign a new function to the returned object, it does not have the concept of the original seq variable.

Gilad Artzi
  • 3,034
  • 1
  • 15
  • 23
1

As @devnull69 has mentioned, you have created a closure and your seq is looking on global. If you want to modify your methods after the fact, maybe have a look at prototypes.

// Constructor
var Serial_maker = function() {
    var prefix = '', seq = 0;
};

// Define the methods
Serial_maker.prototype.set_prefix = function(p) {
    prefix = String(p);
};

Serial_maker.prototype.set_seq = function(s) {
    seq = s;
}

Serial_maker.prototype.gensym = function() {
    var result = prefix + seq;
    seq += 1;
    return result;
}

// Create the object with new
var seqer = new Serial_maker();

seqer.set_prefix('Q');

seqer.set_seq(1000);

seqer.gensym();

// You can modify the methods on the
// constructor's prototype anywhere in the code
// and it will apply to all objects that were created
// with it.
Serial_maker.prototype.set_seq = function(s) {
    seq = 2000;
}

seqer.set_seq();

console.log(seqer.gensym()); // Output is 'Q2000'
wot
  • 845
  • 4
  • 10
  • This makes the `seq` and `prefix` variables global, they are not those defined in `Serial_maker`. It would be better to make them instance variables (`this.seq`, `this.prefix`); but I'm assuming the OP has them *"private"* for a reason. I'm not sure why prototypes are necessary here, considering there is only one instance. – Spencer Wieczorek Jun 08 '16 at 07:45
  • @SpencerWieczorek so have this? this.prefix = '', this.seq = 0; – wot Jun 08 '16 at 07:48
  • Well it's an assumption, the OP might want them to be static. They defined why is a certain thing is not happening in their code, it's not clear if or how they want to change the code so it works as they would expect. – Spencer Wieczorek Jun 08 '16 at 07:53
-1

Try using your var seq = 0 as global. i.e. Without var.

var prefix = ''; // scope :- local

seq = 0; // scope :- global
Samir
  • 1,312
  • 1
  • 10
  • 16