is there a way to inject privileged methods after an object is constructed?

346 views Asked by At

I'm trying to write fully automated unit tests in JavaScript and I'm looking for a way to read some private variables in various JS functions. I thought I recalled a way to inject privileged members into a function/object (and found an overwhelming occurrence of "no such thing as private in JS") and yet I can't find any resources indicating how.

I'm trying to read through the properties of .prototype but if there's a way, someone out here would know where to direct me faster than I'd find on my own.

Thanks

Update

  1. Privileged means a function that is usable from outside an object and has access to read "private" variables (variables otherwise unable to read from outside). See http://javascript.crockford.com/private.html for Crockford's explanations.

  2. A sample of the function I'm trying to inject to is o2, where I need to validate the value of x (this is a simplified example, the actual code does some transformations and sends them off to other functions which I plan on testing separately).

    var o2 = function() {
        var x = 'me';
    };
    

Update 2: Thanks to everyone who's taken the time to respond. I'm seeing that the overwhelming response here is, "private is private" despite the commentary I see in other SA questions where people say "nothing in JS is private". I guess that is more like rhetorical commentary rather than what I was hoping was some kind of insight into a potential loophole I didn't yet know about.

4

There are 4 answers

2
Robert Koritnik On BEST ANSWER

Correct answer to your question

Even if we try to help you as much as we can, the correct answer to your question is simple:

...you can't

What good would closure variables be if we could access them directly from outside of closure?

if you had an object with private variables, they wouldn't be accessible outside function closure, which is the constructor function.

var c = function() {
    var priv = "private";
    this.get = function() {
        return priv;
    };
}

var o = new c();
o.injected = function() {
    return priv; // ERROR!!!!!! priv doesn't exist in function scope
};

It is of course different matter if you enclose the whole thing inside a function closure but then you wouldn't have object privates, but rather function closure internals that would be shared among all prototypes within this closure.

(function(){

    var intrn = "internal";

    // omit "var" to make it global
    c = function() {
        this.get = function() {
            return intrn;
        };
    };

    // omit "var" to make it global
    o = new c();
    o.injected = function() {
        return intrn; // WORKS
    };
})();

o.injected();

but this is different than object privates...

0
Jared Smith On

Know that I am quite late to the party, but yes it is possible. Although AFAIK it requires use of eval() and a helper method:

function foo(){
    var a = 'a';
    this.addMethod = function(prop, val){
        this[prop] = eval('(' + val.toString() + ')');
    }
}
var bar = new foo();
bar.b = 'b';
var Fn = function(){return a + this.b}
bar.addMethod('getValue', Fn);
bar.getValue(); //yields 'ab'

You can use eval() in this case to redefine the function within the context of the closure. However, using eval() is dangerous, ESPECIALLY don't eval() any user input, EVER. However, for use in a testing suite/script it should be fine.

2
jfriend00 On

I'd suggest you read Crockford's treatise on how to achieve privileged and private in javascript objects.

If by privileged, you mean methods that are not accessible outside the object, but are callable by other methods and are actually methods on the object, then there really isn't any way to do that because one you put a method on the object, javascript let's anyone call it.

If you just wanted to add a function that was only callable by methods, you could do that by having a private member variable (see how Crockford implements that) that was an object and you could put the methods on that object. Then all existing methods (implemented the way Crockford suggests in the constructor to have access to the private member data) could call those methods. They would technically be members of a different object, but could be given private access to your object's instance data if needed.

It's all pretty convoluted so you'd probably get a better answer if you described the problem you're really trying to solve.

0
bfavaretto On

I don't think you can do that. Consider the following code:

function foo() {
    var privateVar = 10;            
    this.privilegedMethod = function() {
         return privateVar;   
    }
}
var obj = new foo();

Here, privilegedMethod has access to privateVar, since it's part of the closure created when the method was defined. Of course, you can always attach a new method to the object after instantiation:

obj.newMethod = function() { return "hello" };
alert(obj.newMethod()); // alerts "hello"

But this new method won't have access to privateVar.