4

I am writing a Javascript API library that provides consumers with an interface that enables them to interact with our backend web services. It is envisioned that a consumer will be writing a javascript client web application that draws heavily on the API provided for by the library.

I have come up with this "pattern" for maintaining state and making functionality "available" as certain criteria are met (for example, an authenticated user is logged in client-side).

Is this an appropriate way to achieve that end? Or am I unwittingly breaking some convention or best practice that will bite me later on?

// file: clientApi.js (library)

ClientObject = function () {
    this.objectname = "a client class";
}

ClientObject.prototype.loginUser = function(name) {
    this.loggedin = true;
    if (typeof this.User === 'undefined') {
        this.User = new ClientObject.User(name);
    }
}
ClientObject.User = function (name) {
    this.username = name;
}

ClientObject.User.prototype.getProfile = function() {
    return 'user profile';
}

// file: app.js (consuming application)

var testClient = new ClientObject();
console.log('testClient.User = ' + (typeof testClient.User)); // should not exist
testClient.loginUser('Bob'); // should login 'bob'
console.log('testClient.User = ' + (typeof testClient.User)); // should exist
console.log(testClient.User.username); // bob
testClient.loginUser('Tom'); // should not do anything
console.log(testClient.User.username); // bob still
console.log(testClient.User.getProfile()); // tada, new functionality available

My question: is this approach valid? Is there a pattern that I'm touching on that might offer a better explanation or method of achieving my end goal?

I asked a similar question here with a bunch of other ones, unfortunately the above code was somewhat lost in the noise: Javascript: creation of object from an already instantiated object versus the prototype

Community
  • 1
  • 1
Ross
  • 472
  • 1
  • 4
  • 11

1 Answers1

2

Your API should have some secrets. That's why do not make all your functions public. Let's analyze some parts of your code:

testClient.loginUser('Tom'); // should not do anything

But your implementation allows client to do next:

testClient.User = new ClientObject.User(name);

Now user will be changed to "Tom".

Let's change your clientApi.js code, using revealing prototype pattern:

ClientObject = function () {
    this.objectname = "a client class";
    this.username;
    this.User;
    this.loggedin;
 }    

ClientObject.prototype = function() {  
var loginUser = function(name) {
    this.loggedin = true;
    if (typeof this.User === 'undefined') {
        this.User = new User(name);
    }
};

var User = function (name) {
    this.username = name;
};

User.prototype.getProfile = function() {
    return 'user profile';
};

return {
    loginUser : loginUser
}
}()

Now client cannot change logged in User like in first version of the library. You can use some variations, but that's the idea.

Max Tkachenko
  • 504
  • 1
  • 6
  • 17