privaskey, prototype-friendly privacy

by plus5keen

HTML

<!DOCTYPE html>
<html>
    <head>
        <title></title>
    </head>
    <body>
        <h2>Output</h2>
        <div class="output"></div>
        <p>additional output goes to development console</p>
    </body>
</html>

JavaScript

// AMD-to-global shim
function amdToGlobal(global, key) {
    if (!global || global.define) { return; }

    var oldDefine = global[key];

    global[key] = global.define;
    global.define = function(cb) { // TODO add deps?
        global[key] = cb();
        global.define = oldDefine;
    };
}

amdToGlobal(window, 'privaskey');

// privaskey
// Simple Prototype-Friendly Privacy
// by Cory Watson
// call privaskey(obj) to access obj private data
// call privaskey.make() to create a private privacy object for truly private data
// call privaskey.makeFriend(i) to share a privaskey object with another module, allowing it to access your private data
// use multiple privaskey objects to share only a portion of your private data
define(function() {
    'use strict';

    var idCounter = 0;

    function getId() {
        return '__PRIVASKEY.' + String(idCounter++) + '.' + Math.floor(Math.random() * 65536) + '__';
    }
    
    var has = Object.prototype.hasOwnProperty;

    function make() {
        var p, id = getId();

        p = function privacyGet(obj) {
            return obj[id] || (obj[id] = {});
        };

        p.make = make;

        p.makeFriend = function(i) {
            if (!i || i < 0) { i = 1; }

            return function makeFriend() {
                if (!i) { return; }
                i--;
                return p;
            };
        };
        
        p.makeProp = function(key) {
            return function(value) {
                if (typeof value === 'undefined') {
                    return p(this)[key];
                }

                return p(this)[key] = value;
            };
        };

        p.makeProps = function(keyMap) {
            var result = {};

            for(var key in keyMap) {
                if (has.call(keyMap, key)) {
                    result[key] = p.makeProp(keyMap[key]);
                }
            }

            return result;
        };

        return p;
    }

    return make();

});

// Design...