Soon
Soon

Reputation: 151

Inner function cannot access outer function variable after being changed

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 =)

Upvotes: 2

Views: 409

Answers (4)

wot
wot

Reputation: 845

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'

Upvotes: 1

Samir
Samir

Reputation: 1368

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

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

seq = 0; // scope :- global

Upvotes: -1

devnull69
devnull69

Reputation: 16544

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

Upvotes: 4

Gilad Artzi
Gilad Artzi

Reputation: 3084

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.

Upvotes: 2

Related Questions