0

I have a namespace in the following format allowing for public and private members:

function A() {
    return('a');
}

namespace1 = (function () {
    // private
    namespace2 = (function() {
        // private
        prC = function () {
            return(namespace1.puB() + 'c');
        };
        puC = function () {
            return(prC());
        };
        // public
        return({
            puC: puC
        });
    })();
    prB = function () {
        return(A() + 'b');
    };
    puB = function () {
        return(prB());
    };
    // public
    return({
        puB: puB,
        namespace2: namespace2
    });
})();

document.write('A() = '); try {  document.write(A()); } catch (ex) { document.write('inaccessible'); }
document.write('<BR />');
document.write('namespace1.prB() = '); try {  document.write(namespace1.prB()); } catch (ex) { document.write('inaccessible'); }
document.write('<BR />');
document.write('namespace1.puB() = '); try {  document.write(namespace1.puB()); } catch (ex) { document.write('inaccessible'); }
document.write('<BR />');
document.write('namespace1.namespace2.prC() = '); try {  document.write(namespace1.namespace2.prC()); } catch (ex) { document.write('inaccessible'); }
document.write('<BR />');
document.write('namespace1.namespace2.puC() = '); try {  document.write(namespace1.namespace2.puC()); } catch (ex) { document.write('inaccessible'); }

Output:

A() = a
namespace1.prB() = inaccessible
namespace1.puB() = ab
namespace1.namespace2.prC() = inaccessible
namespace1.namespace2.puC() = abc

How might I go about appending both public and private members to such a namespace (IE: from different files)?

Here's a JSFiddle.

CoryG
  • 2,429
  • 3
  • 25
  • 60
  • That's just a bunch of self invocing functions that returns objects, and the problem is that the returned objects don't contain the properties you are trying to access, no such thing as declearing something privat or public in JS. To add more methods to an object you just do it with dot or bracket notation, and functions can be prototyped. As you are not declearing those variables with the `var` keyword, they are global, and can be accessed in the window scope, see this [**FIDDLE**](http://jsfiddle.net/qQtGA/1/) ??? – adeneo Feb 17 '13 at 02:23
  • In your context, `prB()` is not private at all. It is globally. Try running `prB()`! – Amberlamps Feb 17 '13 at 02:33

3 Answers3

2

"How might I go about appending both public and private members to such a namespace..."

Well, your functions are exposed because you didn't properly declare your variables with var.

But once you fix that, you can add more exposed properties (since all properties are exposed) from any code that can reference your namespace objects.


Adding more properties that reference local (the proper term for private) functions, you'd need a new function and variable scope.

Just invoke a function that references the namespace objects, create some functions inside that function, and add properties that reference those local functions.

// Other file

(function() {
    var newLocalFunc = function() {
        // local function
    }

    var anotherLocalFunc = function() {
        // local function
    }

    namespace1.exposedFunc = function() {
        return newLocalFunc()
    }
    namespace1.namespace2.anotherExposedFunc = function() {
        return anotherLocalFunc()
    }
})();

And again... don't forget to put var before your variables in the original code.

the system
  • 9,244
  • 40
  • 46
1

Any variable declared without the var keyword will be in the global scope. So your puB() function is NOT inaccessible or private, it is just not a member of the object returned by the namespace1 function. Try window.prB() for example, you'll see that method exists within the global scope of the window object.

<head>
    <script type="text/javascript">
        obj1 = {}; //in global scope
        var obj2 = {}; //in global scope. Although used the var keyword, this line itself is in the global scope; so the variable.
        function someFunc() {
            obj3 = {}; //in global scope
            var obj4 = {}; //'so-called' private (inaccessible from global scope)
        }
    </script>
</head>

For combining two different JS files under the same 'namespace' (or let's say object):

File-1.js

var namespace1 = (function() {
    // some code...
    var namespace2 = (function() {
        // some code...
        return {
            obj2: 'value2'
        };
    })();

    return {
        obj1: 'value1'
    };
})();

File-2.js

namespace1.namespace3 = (function() {
    // some code...
    var ns4 = (function() {
        // some code...
        return {
            obj4: 'value4'
        };
    })();

    return {
        obj3: 'value3',
        namespace4: ns4
    };
})();

What is what:

  • namespace1 is declared inside the global scope; so it is accessible from anywhere and it is our main object.
  • namespace2 is inaccessible (private).
  • namespace3 is inaccessible in the global scope but accessible as a member of namespace1; e.g.: namespace1.namespace3.
  • namespace4 is accessible as a member of namespace1. e.g.: namespace1.namespace4.

So; the members of our main object namespace1 is:

namespace1 = {
    obj1: String,
    namespace3: {
        obj3: String,
        namespace4: {
            obj4: String
        }
    }
};
Onur Yıldırım
  • 32,327
  • 12
  • 84
  • 98
0

You are a long way from Kansas, here.

You can't "declare" things as public or private.
As long as you define things inside of function, and then choose to return specific things, or append them to an object/array which you passed in as an argument, then you will have "public" (outer) access to those things, after the function returns.

In order to have "private" access, you return a function which references something on the inside.

var Wallet = function (amount, overdraft_limit) {
    var balance = 0,
        overdraft = overdraft_limit || 0,

        deposit_funds = function (funds) { balance += funds; return true; },

        withdraw_funds  = function (request) {
            var funds = 0;
            balance -= request;
            funds = request;
            return funds;
        },

        validate_request = function (pin) { /* ... */ },

        sufficient_funds = function (val) { return val <= (balance + overdraft); },

        add = function (pin, deposit) {
            if (!validate_request(pin) || deposit <= 0) { return false; }

            var result = deposit_funds(deposit);
            return result;
        },

        deduct = function (pin, withdrawl) {
            if (!validate_request(pin) || withdrawl <= 0) { return false; }
            if (!sufficient_funds(withdrawl)) { return false; }

            var funds = withdraw_funds(withdrawl);
            return funds;
        },

        check = function () { return balance; },

        public_interface = { deduct : deduct, add : add, check : check };

    return public_interface;
};


var myWallet = Wallet(30, 20);

var cash = myWallet.deduct(40);
cash;             //  40
myWallet.check(); // -10

myWallet.balance = 40000000000;

cash = myWallet.deduct(4000);
cash;  // === false

By building functions inside of my "constructor", which have access to balance, the variable that I return that "public" object to can call methods to interact with the "private" data, but can't access it or modify it through any method but to use those "public" functions.

Nesting this stuff 8-layers deep, using IIFEs uses the exact-same concept of closure which I just demonstrated.

Explicitly decide what you're going to return and what you are not.
The functions which you send into the world are public. The functions/etc inside of the function, which weren't returned or attached to an object are private.
They have been closed over, by the "constructor" function which returned, and now they are 100% inaccessible, except by using the functions which were built inside of the constructor, which reference the private vars, and were returned as public methods.

Norguard
  • 26,167
  • 5
  • 41
  • 49