简体   繁体   中英

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

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

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.

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'

Try using your var seq = 0 as global. ie Without var.

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

seq = 0; // scope :- global

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM