Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript closures, maintain outside object

I've been using Javascript closures to protect variables by making them local to the returned functions, such as:

closure = function() {
    var secretVar = 'Secret';

    return {
        "msg" : function() {
            console.log(secretVar);
        }
    };
}();
console.log(closure.secretVar); // Undefined
closure.msg(); // Secret

I feel that I have a pretty good grasp of that, giving me the ability to control how inner variables are accessed if at all.

I'm now running into this problem

closure = function() {
    var secretVar = ['Secret One','Secret Two'];

    return {
        "del" : function(modMe) {
            modMe = secretVar;
            modMe.slice(1,1);
            console.log(modMe);
        }(secretVar),
        "secretVar" : function() {
            console.log(secretVar);
        }
    };
}();
closure.del(); // Secret One
closure.secretVar(); // Secret One

I want closure.del() to return Secret One, but I want the secretVar to remained untouched, however, it's not. The del() function is modifying the reference rather than a copy, and I'm unsure of how to get it to copy secretVar and modify that.

I'm guessing it's going to be in the form of

(function(y) {
    //..Body that changes y
})(secretVar)

but I haven't been able to get that to work. Any ideas?

like image 631
A Wizard Did It Avatar asked Feb 25 '23 21:02

A Wizard Did It


2 Answers

Your problem actually has nothing to do with closures. When you do:

modMe = secretVar;

You are just creating a new variable pointing to the same array. What you do to one will be reflected in both variables, since they are pointing to the same thing.

If you want to perform some sort of modification on the array (while maintaining the original), you need to copy it first:

var copied = [];
for(var i = 0; i < secretVar.length; i++){
    copied.push(secretVar[i]);
}

Edit: As an aside, when you say you are using closures to "protect variables" you're not protecting them from being modified by the returned functions that performed the closure. You just made it so that the variable is inaccessible from outside the scope of those functions. But, inside the scope, such as when you do your slice, the variable is there and accessible to that function and is not "protected" just because it is a closure.

Edit 2: If you are going to be copying the array frequently, you can eliminate some of the irritation of the iteration by creating a closured function to do the copying for you:

closure = function() {
    var secretVar = 'Secret';
    var clone = function(){
        var clonedArr = [];
        var length = secretVar.length;
        for(var i = 0; i < length; i++){
            clonedArr.push(secretVar[i]);
        }
        return clonedArr;
    }

    return {
        "msg" : function() {
            var duplicate = clone();
        }
    };
}();
like image 51
Matt Avatar answered Mar 07 '23 22:03

Matt


Very close -- the form is:

(function(y) {
    return function() {
        // that changes y
    };
})(secretVar)

NOTE: This will still pass a reference, and any destructive or altering operations will still affect secretVar. You'll need to make a deep copy of secretVar if you want to avoid altering it.

SEE: http://jsfiddle.net/B3ryr/2/

like image 33
Sean Vieira Avatar answered Mar 07 '23 21:03

Sean Vieira