From scratch pub sub definition and implementation I am finished with my implementation of PUB/SUB or Observer pattern, however I just want to see any ways that I may be able to improve this pattern. I wanted to be able to use the typical PubSub pattern except add performance enhancements by using the new key word to instantiate each new instance of a PubSub object, as well as make sure that the initialize fn as well as all of the public methods are chain-able.

Here is my PubSub definition:

(function(global) {
'use strict';

var newPubSub;
global.PubSub = {
    core: function core() {},
    init: function(moduleNs) {
        if (!global[moduleNs]) global[moduleNs] = new PubSub.core();
        else throw new Error('A module has already been initialized under this namespace');
        newPubSub = global[moduleNs];
        return newPubSub;
    }
};

var instance = PubSub.core.prototype;

/**
 * Will check for the existance of prev array under this ns and if none exists it will create
 * a new prop with the ns and the function as the sole member of the array. If an array already
 * exists under this namespace then the function is simply pushed into that namespaces array of
 * methods that it will be triggered when that ns becomes published.
 **/
instance.sub = function(ns, fn) {
    if (!newPubSub[ns]) {
        newPubSub[ns] = [fn];
    }
    else if (Array.isArray(newPubSub[ns]) &amp;&amp; newPubSub[ns].length &gt; 0) {
        newPubSub[ns].forEach(function(savedFn) {
            if (fn === savedFn) throw new TypeError('This function already exists under this namespace, please provide a new method for this namespace or add a new namespace to hold this method/fn');
            else {
                newPubSub[ns].push(fn);
            }
        });
    }
    return this;
};

/**
 * Will remove all methods for a listener and the listener ns is not provided,
 * or will remove a single method from a listener if the ns provided has a matching method/fn
 **/
instance.unsub = function(ns, fn) {
    function revokeAllMethods(ns) {
            if (newPubSub[ns]) {
                delete newPubSub[ns];
            }
    }
    // loops through all the methods in a namespace provided and compares to see if the method provided exists, if it does it will be removed
    function revokeSpecificMethod(ns, fn) {
        newPubSub[ns].forEach(function(savedMethod, idx) {
            // Remove the method that matches the one provided to unsubscribe
            if (fn === savedMethod) newPubSub[ns].splice(idx, 1);
            // Otherwise an error will be thrown
            else throw new Error('No method match found under the namespace '+ns);
        });
    }
    if (typeof ns === 'string') {
        if (!fn) {
            revokeAllMethods(ns);
        }
        else if (typeof fn === 'function') {
            revokeSpecificMethod(ns, fn);
        }
    }
  return this;
};

/**
 * Will trigger an event with provided params on any methods under the ns triggered
 */
instance.pub = function(ns, params) {
    if (!newPubSub[ns]) throw new TypeError('No method found under the namespace "' + ns + '" inside of Object. It has either been unsubscribed or never existed.');

    newPubSub[ns].forEach(function(fn) {
        fn.apply(null, params);
    });
    return this;
};

})(window);


Implementation:

PubSub.init('test');

test.sub('alert', function(msg){
    alert(msg);
}).pub('alert',['bob']).sub('somethingelse', function(){
    alert('look ma no params');
}).pub('somethingelse').pub('alert',['bob']).unsub('alert').pub('alert',[12]);
Error checking

Seems like you don't do all the error checking you'd need. For example, in this function

instance.sub = function(ns, fn) {
    if (!newPubSub[ns]) {
        newPubSub[ns] = [fn];
    }
    else if (Array.isArray(newPubSub[ns]) &amp;&amp; newPubSub[ns].length &gt; 0) {
        newPubSub[ns].forEach(function(savedFn) {
            if (fn === savedFn) throw new TypeError('This function already exists under this namespace, please provide a new method for this namespace or add a new namespace to hold this method/fn');
            else {
                newPubSub[ns].push(fn);
            }
        });
    }
    return this;
};


fn falls through the cracks if newPubSub[ns] is not an array but already exiss. Wouldn't you want to throw an error?

Similarly, you might also want to check that newPubSub[ns] has the expected form in unsub and that apply can be applied to each member of 

Use closures to enforce encapsulation

All my concern about error checking relates to the fact that you are creating normal properties in these objects with your pub-sub methods, meaning that in the intervening time, a user can forget he was using a certain keyword with pub-sub and might use it for something else.

For example, here I corrupt your test variable by doing something entirely different with the alert key and forgetting I was using that for my pubsub functionality:

PubSub.init('test');

test.sub('alert', function(msg){
    alert(msg);
}).pub('alert',['bob'])

test['alert'] = "hi!"; // oops your 'alert' chain is gone

test.pub('alert', ['joe'])  //doesn't work


I think you'll want to restructure this to something like the following:

function pubsub() {
     var pub_arrays = {}
     return {
        sub: function(ns, fn){ 
                if(!pub_arrays[ns]) pub_arrays[ns] = [fn] 
                else p
                },
        pub:  .... and so on ....

    };
}


In this way all your methods will have access to the object that holds the publishing arrays (one array for each key word) but outside users won't have access to this so they won't be able to change it. 

Variable scoping in JavaScript is not a strong suit of mine, but I think something like this, using closures for encapsulation, is where you want to be if you don't trust the user, or yourself, not to accidentally...or maliciously...mess with your pub/sub methods.

Additionally, it looks like the most recent version of JavaScript may provide Class methods to encapsulate data. Read more on that in these SO posts:


https://stackoverflow.com/questions/29455692/how-does-closure-reify-the-data-encapsulation
https://stackoverflow.com/questions/8729714/closures-vs-classes-for-encapsulation