开发者

Can you extend an object that has access to private properties with a function that can also access those private properties?

开发者 https://www.devze.com 2023-03-31 03:52 出处:网络
I am creating an object inside of an enclosure. Also in the enclosure are private properties that the object\'s functions can access - and this works as expected.

I am creating an object inside of an enclosure. Also in the enclosure are private properties that the object's functions can access - and this works as expected.

My issue: I want others to be able to extend my object with functions of their own (functions from a different context), but those functions will also need access to the same private properties - and I have not been able to find a way to make this work.

I've tried various configurations of .call, and also wrapping their function in a new function, amongst other things. I feel like I've gotten close to a solution, but have just fallen short.

Here's a bit of simplified example code that accurately reflects my situation:

//extension object
//fn2 can be any function, with any number of arguments, etc.
var obj1 = {};
obj1.fn2 = function (s1, s2){ console.log(priv); };

//actual object
var obj2 = (function (){
    //private property
    var priv = "hello world";

    //return object
    var obj3 = {};

    //return object's native fn (works)
    obj3.fn = function (s){ console.log(priv); };

    //extension happens here - but is obviously not correct
    obj3.fn2 = obj1.fn2;

    //return object
    return obj3;
})();

//try output
obj2.fn("goodbye world"); //works
obj2.fn2("goodbye world", "thx 4 teh phish"); //fails

Any insight would be appreciated. And I totally understand if what I want just isn't possible - but it sure seems like it should be :P

EDIT: Thank you all for the responses. I fully understand that the properties are more easily accessed as public, and that normally inherited objects won't have access to them otherwise. However, since the new function is being attached to the original object I have to believe there's a way to use the original context and not the context the new function was created in.

Now, I'm the first to say that eval is evil - and, in fact, I've never used it, or even considered using it, before. However, I'm trying everything I can think of to make this work - and I stumbled across this (seemingly) working solution:

obj3.fn2 = eval(obj1.fn2.toString());

So, if I check to make sure that 开发者_运维百科obj1.fn2 is a typeof function, is there any way this could be harmful to my code? It doesn't execute the function, so I can't see how - but maybe I'm missing something?


Javascript doesn't have a "protected" analog. You either get super private or completely public. From here you can choose to:

  1. Reconsider your class design, and have the subclasses depend only on the public interface of the parent class.

  2. Add getter and setter functions to the public interface. Not necessarily the best thing though as you might just as well make the properties public (besides best practice issues and whatnot)

  3. Just use public properties instead. This is the "natural" way to do OO inheritance in Javascript and is usually not a problem if you use a donvention like adding an underscore to the beggining of the name. As a bonus you can use the prototypal inheritance feature (it is nice knowing how to use this instead of only closure-based classes)

    function Base(){
        this._priv = "Hello world"
    };
    Base.prototype = {
        fn: function(){
            console.log(this._priv);
        }
    }
    
    var obj2 = new Base();
    obj2.fn = function(){ ... }
    


I hate to answer my own question - seems like a bit of a faux pas - but c'est la vie. (because I woke up French today?)

So, while I found that the eval() solution I presented last night in the edit to my original question does seem to be a valid solution, and a proper use of eval for retaining the object's context within the new function, it is far from perfect.

Firstly, it works in FF, but both IE and Chrome seem to hate it (those were the next ones I tried, and I quit trying others after they both failed). Though I'm sure it could probably be made to work across browsers, it seems like a hassle.

Secondly, it does give quite a bit of power to the new function, and as I look at my code more I do like the idea of controlling exactly what these new functions being added to my object get access to.

Thirdly, .eval() is typically pretty slow - and it turns out that .apply() (which is typically faster) just may work well enough.

This is because I realized at some point last night that no new functions on this object will need to set any of the private variables (at least, I'm fairly certain they won't) - and .apply() works fine to pass the values through for them to read.

I'm sure there's more to it than just those 3 things, but for now I think I'm going to go with more of a 'wrapper' solution - something like this:

var f = function (){
    var fauxThis = {};

    fauxThis.priv = priv;

    obj1.fn2.apply(fauxThis, arguments);
};

obj3.fn2 = f;

//(To be placed where I had "obj3.fn2 = obj1.fn2;")

I am certainly willing now to consider the use of eval() in very specific cases - and may even revisit this specific use of it before I make my final decision of which direction to take. (especially if I can think of a case where the private value would need to be set)

Thanks all for your input!


The quickest and easiest solution is to prefix any supposedly private properties with the underscore (_).

Personally I like to bottle my private properties into a single object which would be placed on the object, like so:

obj.publicProp = 20;

obj._.privateProp = true;

I wouldn't worry so much about it though, the underscore is basically a universal symbol for private so those using the script will know that it's private and shouldn't be touched. Or, better yet, just leave it out of the public documentation ;)

There are other methods and you can use which do emulate "true" protected variables, but they're not the best as they avoid garbage collection, and can be clunky to use.

0

精彩评论

暂无评论...
验证码 换一张
取 消