1

This is a strange one, but I'm exploring it to see if it's possible.

Let's say that I have a .NET application where I am using PubSub. I want a way to define the topic string using chained objects (not functions). The goal is to allow me a way of defining strings that lets me to take advantage of Visual Studio's IntelliSense and reduce the likelihood of spelling errors.

Here's an example:

/* Manual way */
var topic = "App.Navigation.CurrentItem"



/* Desired Solution */

// ... define the objects here ...

var topic = App.Navigation.CurrentItem;
console.log(topic); // "App.Navigation.CurrentItem"

var topic2 = App.Footer.CurrentItem;
console.log(topic2); // "App.Footer.CurrentItem"

I'd like each object to be responsible for outputing it's own value, and have the chaining process responsible for joining itself to the previous chained object via a predefined separator (in my case, a period [.]).

I've been playing with JavaScript getter syntax, but I'm curious if there's a better way.

Has anyone done something like this before, and if so, how did you solve it?

Travis Wilson
  • 130
  • 1
  • 8
  • Why do you want the chaining process to be responsible for building the string? Why not have code that just says `App.Navigation.CurrentItem = "App.Navigation.CurrentItem"`? – StriplingWarrior Oct 05 '15 at 21:19
  • My job is R&D, so I'm always trying to find ways to make things easier for my team. Being able to define a variable to always return one value, regardless of its position in a chain, keeps my code DRY. It's honestly not a need to have. I'm just curious if anyone has a way to use JS to do it. – Travis Wilson Oct 06 '15 at 15:36

2 Answers2

1

You're requirements aren't totally clear to me, but are you looking for something like this?

function namespace(ns) { this._ns = ns; }
namespace.prototype.toString = function() {return this._ns};
namespace.prototype.extend = function(suffix) {
    return new namespace(this._ns + "." + suffix)
};

Usage:

App = new namespace('App');
App.Navigation = App.extend('Navigation');
App.Navigation.CurrentItem = App.Navigation.extend('CurrentItem');
console.log(App.Navigation.CurrentItem.toString()); // "App.Navigation.CurrentItem"
StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
  • 1
    This works perfectly - you nailed it! I wouldn't have thought to go this simple. Makes total sense, and you've taught me something here. Hug thanks! – Travis Wilson Oct 06 '15 at 16:02
0

This is what I ended up with after reviewing StriplingWarrior's answer:

function Namespace(name, config) {
    if (typeof name === "object") {
        config = name;
        name = null;
    }
    config = config || {};

    this._ns = name;
    this.define(config);
}
Namespace.prototype.toString = function() { return this._ns };
Namespace.prototype.define = function(config, base) {
    base = base || this;

    for (key in config) {
        var name = (base._ns) ? base._ns + "." + key : key;
        base[key] = new Namespace(name);
        base.define(config[key], base[key]);
    }

    return base;
};

Usage:

var App = new Namespace("App", {
    Navigation: {
        Items: {
            Current: {}
        }
    },
    Content: {},
    Footer: {
        Items: {
            Current: {}
        }
    }
});

console.log(App.toString()); // App
console.log(App.Navigation.Items.Current.toString()); // App.Navigation.Items.Current
console.log(App.Footer.toString()); // App.Footer

I also wrote a convenience method to reduce the toString():

function NS(namespace) {
    return namespace.toString();
}

console.log(NS(App.Navigation.Items.Current));

Thanks again to StriplingWarrior for the the help!

Travis Wilson
  • 130
  • 1
  • 8