0

I'm building out some node.js modules and I have some libraries I'd like to push into this object

in this senario, I have

app.js

var api = require('./scripts/api.js');
var oauth = require('./scripts/oauth.js');
var db = require('./scripts/db.js')
var libraries  = {
    api : api,
    db : db,
    oauth : oauth,
}

var modules = require('./scripts/module.js');
modules.init(app, libraries);

module.js

module.exports = { 

    init : function(app,libraries) {
        for (key in libraries) {
            if (libraries.hasOwnProperty(key)) {
                this[key] = libraries[key]
            }
        }

        this.oauth.init(app,libraries);
    }
}

api.js

module.exports = { 

init : function(app, libraries) {
    for (key in libraries) {
        if (libraries.hasOwnProperty(key)) {
            this[key] = libraries[key]
        }
    }
    app.get('/api/linkedin/posts', function (req, res) {

        //get the credentials
        var userid = req.session.user_id;
        var credentials = '';
        getCredentials('linkedin',userid)
            .then(function(result) {
                this.db.store(credentials = JSON.parse(result))
                    })
    });
}, 
}

and it works fine, What I'd like to happen however is instead of pushing it onto the module object itself. to push it onto the object scope so that I don't have to add this.library.function() to everything. In this way I can just call oauth.init() and access the library directly, is there any good way of doing this?

What I'd like to accomplish would be to have the same affect as if I did the following instead, I'm just trying to make these bootstraping methods magic

module.js

var api = {}
var oauth = {}

module.exports = { 

    init : function(app,libraries) {
        api = libraries.api
        oauth = libraries.oauth

        oauth.init(app,libraries);
    }
}

Here's a fiddle demonstrating the problem http://jsbin.com/cadejukijudu/1/edit

Matt Bucci
  • 2,100
  • 2
  • 16
  • 22
  • Could you show how you are invoking? – cgatian Aug 15 '14 at 00:42
  • @cgatian, I'd like a way to bind a variable into the scope of the object from within init, as if i had done var oauth = {} and var api = {} above module.exports and then assigned the value from within init. I've Updated the question – Matt Bucci Aug 15 '14 at 00:42
  • So are you trying to avoid api.init(), oauth.init()? – cgatian Aug 15 '14 at 00:43
  • @cgatian no I'm fine with that, I want to avoid placing this. in front of each call to a library like this.oauth this.api, I want to just call oauth.init() api.init() not this.oauth.init() – Matt Bucci Aug 15 '14 at 00:44
  • Can you modify the modules.init function? – cgatian Aug 15 '14 at 00:47
  • @cgatian yes, I can modify anything necessary – Matt Bucci Aug 15 '14 at 00:48
  • 1
    Objects don't have scopes, only functions do, and no you cannot progammatically access them. Related: [Add variable to a functions scope](http://stackoverflow.com/q/24097767/1048572), [JS class without constant reference to “this” for member access](http://stackoverflow.com/q/24982471/1048572) – Bergi Aug 15 '14 at 02:03

2 Answers2

1

@Matthew Bucci: Your question is very confusing to me - not because of your coding style, but because of the description of the problem and the program design -, so I'm starting out by slightly rewriting your question and adding comments. Hopefully the question and its answer will become evident; If not to me, then someone else.


Your Question:

App.js

var libraries = {
    "api": require('./scripts/api.js'),
    "db": require('./scripts/db.js'),
    "oauth": require('./scripts/oauth.js')
};

var modules = require('./scripts/module.js');
modules.init(app, libraries);
// Where does the app variable come from?
// The naming of your script "module.js" is confusing,
// because node has a built-in module called module...

Module.js

module.exports = {
    "init": function (app, libraries) {
        var key;
        for (key in libraries) {
            if (libraries.hasOwnProperty(key)) {
                this[key] = libraries[key];
                // So you effectively want to copy all properties of libraries
                // to the object in the variable modules in app.js?
            }
        }
        this.oauth.init(app, libraries);
        // I assume the oauth object, required in app.js, also has an init property.
        // So you effectively want to copy all properties of libraries to the modules
        // object and to the oauth object contained in the modules object!?
        // Just pointing out, you're using the same app variable passed in app.js,
        // which in this context is an argument of the module.js .init function.
    }
};

api.js etc.


Guessed answer:

init.js

global.api = require('./scripts/api.js');
global.oauth = require('./scripts/oauth.js');
global.db = require('./scripts/db.js');
// Any initialization of required objects is best done when the respective code is
// evaluated, i.e. the first time they're required; Initialization code should be 
// included in respective modules.

app.js

api; // Not available yet!
require('./scripts/init.js');
api; // Refers to the result of require('./scripts/api.js') initialized in init.js
oauth; // idem, etc.

In conclusion: I think you're dealing with a problem that you shouldn't have to deal with. Objects don't have scope and don't have parents. The property tree formed by nesting objects is a one-way street, because a single object can be the property of multiple other objects; So generically retrieving a reference to the nesting object from the nested object is very unfeasible; It would require you to write a very elaborate search function, which would be very expensive in its execution. If you want to copy (push) the properties of one object to another - whether or not one is nested in the other - just make a common copy function; You will have to explicitly tell the function what needs to be copied onto what.

Functions have scope, and with the let statement blocks statements can have scope. The curly braces of an object are not block statements.

dot slash hack
  • 558
  • 1
  • 5
  • 13
  • good idea and a definite solution due to the global. reference, however I am trying to organize my project in the following manner http://stackoverflow.com/a/18576246/1752064 – Matt Bucci Aug 15 '14 at 21:35
  • 1
    I've now refactored my entire app.js to be just //configure the environment require("./scripts/config.js"); //pull in some helper libraries global.utils = require("./scripts/utils.js"); global.db = require("./scripts/db.js"); global.account = require("./scripts/account.js"); global.oauth = require("./scripts/oauth.js"); global.api = require("./scripts/api.js"); //pull in our routes (dumb function routers) require("./scripts/routes.js") //pull in our views (dumb handlebar templates) require("./scripts/views.js") Thanks for the help – Matt Bucci Aug 16 '14 at 00:24
0

I've found I can force this to work by just declaring it in the init function without a var keyword, the assumed scope is GLOBAL then, which is is terrible practice

http://jsfiddle.net/4wjbyy9g/6/

  this.init = function(libraries)
  {
     for (var key in libraries) {
        var messy = key + " = libraries[key] "

        eval(messy)
     }
     oauth.log('yay!');
  };

the global scope problem can be avoided by manually declaring the vars within the module, but this isn't quite as clean as I'd like it because I have to manually state each variable name. However this is the cleanest solution I've found so far

function module()
{
  var oauth = {} //I don't want to have to write this to keep it out of the global scope

  this.init = function(libraries) {
     for (var key in libraries) {
        var messy = "if (typeof " + key + " !== 'undefined') {"
        messy += key + " = libraries[key] }"

        eval(messy)
     }
     oauth.log('yay!');
  }

  this.test = function() {
     oauth.log(JSON.stringify(oauth))     
  }
}

http://jsfiddle.net/52ea5t0q/6/

Matt Bucci
  • 2,100
  • 2
  • 16
  • 22
  • No, the assumed scope is not within the object, the scope of that variable is now GLOBAL. – Chris Tavares Aug 15 '14 at 22:18
  • @ChrisTavares, oh god that's so much worse – Matt Bucci Aug 15 '14 at 22:19
  • I'm not even sure what "scope is within the object" is supposed to mean. Objects don't have, and aren't scopes. Scopes are part of functions. – Chris Tavares Aug 15 '14 at 22:21
  • @ChrisTavares I guess you're somewhat right, although I'm somewhat fuzzy on what the difference is in this case. Here's a fiddle demonstrating what I'm trying to do I've confirmed that you're right and without a var in the outer function it'll get assigned the global scope. I'm trying to avoid putting in the manual function names for injection http://jsfiddle.net/52ea5t0q/3/ – Matt Bucci Aug 15 '14 at 22:36