Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I "extend" a closure-defined "class" in Javascript?

I have a Javascript "class" defined like so:

var Welcomer = function(name) {
  var pName = name;
  var pMessage = function() {
    return "Hi, " + pName + "!";
  };

  return {
    sayHi: function() {
      alert(pMessage());
    }
  };
};

new Welcomer('Sue').sayHi();

Is there a way to "subclass" Welcomer in such a way that I can redefine the public methods and have access to the private methods and variables? The following will give me access to the public methods, but not to the private ones:

var UnhappyWelcomer = function(name) {
  var pSadMessage = function() {
    // won't work, b/c I don't have access to pMessage
    return pMessage() + " Miserable day, innit?";
  };

  return {
    sayHi: function() {
      alert(pSadMessage());
    }
  };
};
UnhappyWelcomer.prototype = Welcomer(); // failed attempt at inheritance

new UnhappyWelcomer().sayHi();
like image 511
James A. Rosen Avatar asked Aug 24 '10 21:08

James A. Rosen


People also ask

Can you extend a class in JavaScript?

The extends keyword is used to create a child class of another class (parent). The child class inherits all the methods from another class. Inheritance is useful for code reusability: reuse properties and methods of an existing class when you create a new class.

What is disadvantages of closure in JavaScript?

There are two main disadvantages of overusing closures: The variables declared inside a closure are not garbage collected. Too many closures can slow down your application. This is actually caused by duplication of code in the memory.

How does closures work in JavaScript?

A Closure is a combination of a function enclosed with references to its surrounding state (the lexical environment). In JavaScript, closures are created every time a function is created at run time. In other words, a closure is just a fancy name for a function that remembers the external things used inside it.

What are the advantages of closures in JavaScript?

The advantage of closures in javascript is that it allows you to bind a variable to an execution context. var closedIn = {}; var f = function(){ closedIn. blah = 'blah'; // closedIn was just "closed in" because I used in the function, but it was defined outside the function. }


2 Answers

The simple answer to your question is No.

You can't do anything to gain access to those var defined things, unless your function is in the same scope, or you somehow 'make public' the information (by returning it, or setting it on this).

If you have access to edit the original function though, you could rewrite things in such a way that those functions could be "passed" into an extending function, which can alter the "protected" scope of the object. The following code should give a good idea of what I am proposing.

var Welcomer = function(name) {
  var _protected = {
    name: name,
    message: function() {
      return "Hi, " + _protected.name + "!";
    }
  };

  return {
    extendWith: function(extender) {
      extender.call(this, _protected);
      return this;
    },
    sayHi: function() {
      alert(_protected.message());
    }
  };
};

var UnhappyWelcomer = function(name) {
  var self = Welcomer(name).extendWith(function(_protected) {
    _protected.sadMessage = function() {
       return _protected.message() + " Miserable day, innit?";
    };
    // extending the public while still having scope to _protected...
    this.sayHi = function() {
      alert(_protected.sadMessage());
    };
  });
  return self;
};

UnhappyWelcomer('bob').sayHi();
like image 112
gnarf Avatar answered Sep 29 '22 08:09

gnarf


That "class" pattern is not a "class" pattern, it's known as a Module Pattern. It returns an object that has no ties to the function that created it other then availability of it's private variables. The returned object is NOT an instance of the function that created it.

When you call 'new Class()' it does create an instance of that function, but it also returns another object. Any further operations is actually on the returned object and not the instance.

In order to use inheritance, you really need to use prototypical inheritance properly, I suggest you read:

  • Prototypical Inheritance by Douglas Crockford
  • Private Members in JavaScript by Douglas Crockford
  • Prototypes and Inheritance in JavaScript by Scott Allen (note: proto is not standard)

Further reading:

  • Classical Inheritance in JavaScript http://javascript.crockford.com/inheritance.html

Sorry to leave you with reading material, but it seems to me you are exploring possibilities. These articles will give a deeper insight on the matter.

Once you know more on the matter, you will most likely ignore private members alltogether and use the _ prefix and just make it a public member like everyone else ;) It's just easier and private members are pointless anyways.

like image 25
BGerrissen Avatar answered Sep 29 '22 08:09

BGerrissen