1

For creating a JS library, I am internally creating objects using constructor pattern. Now each type of object is in it's own file, so say book is in book.js. All the files are concatenated and then minified.

book.js
--------

function Book (data) {
  this.data = data;
}

Book.prototype.rent = function(name) {
  console.log("Rent the book to " + name);
}

Now once the page with the library is loaded, I can notice that from the browser console one can create book objects directly.

var b = new Book("somedata");

I see 2 issues here

  1. pollution of the global namespace since the Book() object is now visible in the global scope.
  2. Security issue as any one can create objects without namespace from console.

The library is actually under a namespace using a revealing module pattern. Is there anyway the issues I have mentioned above can be safely handled? Anyway to hide the objects from global namespace (console)?

12
  • Where is that revealing module pattern in your code? Commented Dec 15, 2015 at 11:28
  • revealing module pattern is used in the main library code that exposes the top namespace object such as "City.Library". Under this, objects such as Book() mentioned above can be created/destroyed as required. However by accident, these objects are available in global namespace as well. Commented Dec 15, 2015 at 11:45
  • Yes, if you are loading all these files as scripts then they will put those classes in the global namespace. You would need to wrap each of those files in a module pattern (that attaches the respective class to City.Library), or you need to treat the files as modules (ES6 is preferred) and let a module loader/bundler do this work for you. Commented Dec 15, 2015 at 11:47
  • @Bergi - I would prefer to go with approach 1 of wrapping each file in a module pattern. However, I am not able to understand how we can attach the class to the City.Library. Commented Dec 15, 2015 at 11:58
  • Just use City.Library.Book = (function(){ …; return …; }()); and make sure it only gets loaded after the main file that creates the City.Library object. Commented Dec 15, 2015 at 12:02

3 Answers 3

2

What you can do is that you can use require module on server side and create grunt task to run browserify task on entry point file so that all your code will be converted into one file and won't be accessible from global namespace. checkout http://browserify.org for more information.

Sign up to request clarification or add additional context in comments.

2 Comments

As I have mentioned above, I am currently using gulp to concatenate all the js files and uglify them. So at the end I have a single library.min.js which is included by the HTML apps. Even though files are concatenated and uglified, they are still visible in the global env.
@sthustfo If you use browserify then you don't have to use concatenate as it will create 1 js file while resolving all module dependencies.
1

Security issue as any one can create objects without namespace from console.

That's not an issue, anyone can create objects on your namespace from the console as well.

pollution of the global namespace since the Book() object is now visible in the global scope. The library is actually under a namespace using a revealing module pattern.

If you are loading all those files as scripts then they will put the classes declared therein in the global namespace. It's unavoidable to use the global namespace somehow, but you can put all of your objects on that custom library namespace right away, using the revealing module pattern. You would need to wrap each of those files in an IEFE that attaches the respective class to City.Library:

City.Library.Book = (function() {
    function Book (data) {
        this.data = data;
    }
    Book.prototype.rent = function(name) {
        console.log("Rent the book to " + name);
    };
    return Book;
}());

Alternatively, treat the files as modules (ES6 is preferred) and let a module loader/bundler do this work for you automatedly.

4 Comments

Two related questions. + In case I need to create an object of type Book within City.Library sub module, then right now I would have to call new City.Library.Book(). Is there a way by which I do not have to mention the complete namespace for the Book object? Because it feels odd for the code in City.Library to know the complete namespace of Book. Is this something normal?
second question: + I had read that one of the benefits of using the constructor pattern (using prototype mechanism) was that the overall memory required by the library is reduced because the code (text part i.e. function definitions) for all the objects that are created are shared, so the objects will be leaner. Does using this method eliminate the advantage or affect the memory usage in anyway? Bear with me, if I am thinking out aloud? Just trying to make sense of the things.
@sthustfo: Depends on what you mean by "within City.Library sub module". If you are in a method of that object, you could just use this.Book. If not, you'll want to use a shortcut var CL = City.Library at the beginning of your module so that you can avoid repeatedly typing out the whole name
@sthustfo: No, the module patterns don't change anything about how prototypes work. They just ease the structuring of your code and give you an extra scope. You could equally have written City.Library.Book = function Book (data) {…}; City.Library.Book.prototype.rent = function(name) {…}; without the wrapper
0

You can wrap them in closures to keep them away from global, but, there is a fundamental problem with this—you want your functions/constructors/whatevers to be accessible!

Approaches like browserify wrap code in files in closures but keeps track of them so that when you need them you can access them. It uses commonJS modules as a means of accessing and organising modular code. I would suggest reading documentation for browserify as using it would solve both problems, although it would enforce a module system on your end users (I'd say this is generally a good thing, at least it is a worthwhile thing, but, that is for you to decide based on your specific case)

I should also point out that there are other solutions for writing modular code as well, such as webpack or jspm

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.