1

The problem with functional inheritance is that if you want to create many instances then it will be slow because the functions have to be declared every time.

The problem with prototypal inheritance is that there is no way to truly have private variables.

Is it possible to mix these two together and get the best of both worlds? Here is my attempt using both prototypes and the singleton pattern combined:

var Animal = (function () {
  var secret = "My Secret";

  var _Animal = function (type) {
    this.type = type;
  }
  _Animal.prototype = {
    some_property: 123,
    getSecret: function () {
      return secret;
    }
  };

  return _Animal;
}());

var cat = new Animal("cat");

cat.some_property; // 123
cat.type; // "cat"
cat.getSecret(); // "My Secret"

Is there any drawbacks of using this pattern? Security? Efficiency? Is there a similar pattern out there that already exists?

fusilli.jerry89
  • 309
  • 3
  • 11
  • Why would you hard-code an ID into the prototype object? Aren't your IDs instance-specific? – Šime Vidas Mar 25 '13 at 22:13
  • It is just an example. Here I will fix it. – fusilli.jerry89 Mar 25 '13 at 22:22
  • Javascript has zero security, though ES5 has ways of avoiding unintended tampering. The code is fully visible to the client so they can read and modify it at any time. While the getSecret method has access to "private" data, there's nothing to stop a user replacing that method entirely, hence replacing the private data too. However, private, privileged and public members are useful from a design perspective though (e.g. it's more elegant to keep members that are only used internally private and only create public those members that are part of an API). – RobG Mar 25 '13 at 22:50
  • Rob, I understand there is no security on the client side, but is there a way to make a variable secure on the server side? i.e. Nodejs – fusilli.jerry89 Mar 25 '13 at 22:58
  • What do you mean by "*functional inheritance*"? – Bergi Mar 26 '13 at 00:13
  • 1
    "functional inheritance" as described by Douglas Crockford. Here is a link I found that explains it: http://www.richard-foy.fr/blog/2011/10/30/functional-inheritance-vs-prototypal-inheritance/ – fusilli.jerry89 Mar 26 '13 at 00:22
  • RobG, in my pattern you can modify getSecret(), but if you do you can no longer access the secret variable, I don't think. Please correct me if I am wrong. – fusilli.jerry89 Mar 26 '13 at 00:34
  • You are correct. In terms of memory-safety, no outside piece of code can ever access the internal variables, unless you give them access. From a system-safety perspective, there's nothing stopping malicious code from replacing your method (unless you go hardcore, and switch to a 100% sandboxed environment, with a moderator system, using message-passing, giving each module a different instance of the delegate moderator). Because then, you're pretty safe, as long as you aren't talking about client-to-server communication... – Norguard Mar 26 '13 at 00:39

2 Answers2

2

Your pattern is totally fine.

There are a few things that you'd want to keep in mind, here.
Primarily, the functions and variables which are created in the outermost closure will behave like private static methods/members in other languages (except in how they're actually called, syntactically).

If you use the prototype paradigm, creating private-static methods/members is impossible, of course.
You could further create public-static members/methods by appending them to your inner constructor, before returning it to the outer scope:

var Class = (function () {
    var private_static = function () {},
        public_static  = function () {},

        Class = function () {
            var private_method = function () { private_static(); };
            this.method = function () { private_method(); }; 
         };

    Class.static = public_static;
    return Class;
}());

Class.static(); // calls `public_static`
var instance = new Class();
instance.method();
// calls instance's `private_method()`, which in turn calls the shared `private_static();`

Keep in mind that if you're intending to use "static" functions this way, that they have absolutely no access to the internal state of an instance, and as such, if you do use them, you'll need to pass them anything they require, and you'll have to collect the return statement (or modify object properties/array elements from inside).

Also, from inside of any instance, given the code above, public_static and Class.static(); are both totally valid ways of calling the public function, because it's not actually a static, but simply a function within a closure, which also happens to have been added as a property of another object which is also within the instance's scope-chain.

As an added bonus:
Even if malicious code DID start attacking your public static methods (Class.static) in hopes of hijacking your internals, any changes to the Class.static property would not affect the enclosed public_static function, so by calling the internal version, your instances would still be hack-safe as far as keeping people out of the private stuff...
If another module was depending on an instance, and that instance's public methods had been tampered with, and the other module just trusted everything it was given... ...well, shame on that module's creator -- but at least your stuff is secure.

Hooray for replicating the functionality of other languages, using little more than closure.

Norguard
  • 26,167
  • 5
  • 41
  • 49
1

Is it possible to mix functional and prototypical inheritance together and get the best of both worlds?

Yes. And you should do it. Instead of initializing that as {}, you'd use Object.create to inherit from some proto object where all the non-priviliged methods are placed. However, inheriting from such a "class" won't be simple, and you soon end up with code that looks more like the pseudo-classical approach - even if using a factory.

My attempt using both prototypes and the singleton pattern combined. Is there a similar pattern out there that already exists?

OK, but that's something different from the above? Actually, this is known as the "Revealing Prototype Pattern", a combination of the Module Pattern and the Prototype Pattern.

Any drawbacks of using this pattern?

No, it's fine. Only for your example it is a bit unnecessary, and since your secret is kind of a static variable it doesn't make much sense to me accessing it from an instance method. Shorter:

function Animal(type) {
    this.type = type;
}
Animal.prototype.some_property = 123;
Animal.getSecret = function() {
    return "My Secret";
};
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375