1

Suppose I have a Javascript class:

function GeneralClass(a, b, c) { ... }

It is constructed like this:

var g = new GeneralClass(a, b, c);

and I want to create a SpecificClass, which is exactly the same as GeneralClass, but with bound values, a=1 and c=3.

I want to construct this class like this:

var s = new SpecificClass(b);

In other languages, there are several ways to do this:

  • I can make SpecificClass inherit GeneralClass, and have the constructor of SpecificClass call that of GeneralClass with the assignment I want.
  • I can add a GeneralClass field inside SpecificClass, and delegate all method calls to it.

But I am looking for a shorter and more elegant way to do this in Javascript - a way that will enable me to create many different SpecificClass's on the fly.

Erel Segal-Halevi
  • 33,955
  • 36
  • 114
  • 183

3 Answers3

2

You can just make a Specific function that creates a GeneralClass with bound parameters.

function GeneralClass(a, b, c) { ... }

function Specific(b) { 
    var a = 1, c = 3;
    return new GeneralClass(a, b, c);
}

var s = Specific(2);
Steven Wexler
  • 16,589
  • 8
  • 53
  • 80
  • You can even call the function with `new Specific(2)`, for consistency. – Felix Kling Aug 26 '13 at 07:35
  • if you `prototype` it, you will have some performance improvements (if really matters), and generally I think it's a better solution. Also I have a feeling that this code would have some maintenance issues if you use it in serious projects, but I might be wrong ... – Mahdi Aug 26 '13 at 08:10
0

What about something like this: jsfiddle

function GeneralClass (a, b, c) {
    this.a = a;
    this.b = b;
    this.c = c;
}

GeneralClass.prototype.hello = function () {
    console.log("hello");
    console.log(this.a);
    console.log(this.b);
    console.log(this.c);
}

var g = new GeneralClass(1, 2, 3);
g.hello();

function SpecificClass (b) {
    this.a = 1;
    this.b = b;
    this.c = 3;
}

SpecificClass.prototype = new GeneralClass();

SpecificClass.prototype.bye = function () {
    console.log("bye");
    console.log(this.b);
}

var s = new SpecificClass(22);
s.hello();
s.bye();
Mahdi
  • 9,247
  • 9
  • 53
  • 74
  • 1
    Why you shouldn't use `Foo.prototype = new Bar();` to set up inheritance: http://stackoverflow.com/q/17392857/218196. – Felix Kling Aug 26 '13 at 08:31
  • @FelixKling I agree, I just used `new` keyword for the sake of consistency with the original post. – Mahdi Aug 26 '13 at 08:46
0

Ok, I think that above solutions will work. However, there is a one problem. You have to create a new function every time when you want extend GeneralClass. Here is my suggestion. It's a function which returns a function. It accepts as many arguments as you want and if some of them is null it is later replaced with the parameter passed to the newly created function.

var GeneralClass = function(a, b, c) { 
   console.log(a, b, c);
}
var GeneralClassExtender = function() {
    var defaults = [];
    for(var i=0; i<arguments.length; i++) {
        defaults.push(arguments[i]);
    }
    return function() {
        var argsToApply = [];
        for(var i=0, usedArguments=0; i<defaults.length; i++) {
            if(defaults[i] === null) {
                argsToApply.push(arguments[usedArguments]);
                usedArguments += 1;
            } else {
                argsToApply.push(defaults[i]);
            }
        }        
        return GeneralClass.apply({}, argsToApply);
    }
}
var SpecificClass = GeneralClassExtender(1, null, 3);
var AnotherClass = GeneralClassExtender(null, 99, null);
var obj1 = new SpecificClass(10);
var obj2 = new AnotherClass(6, 20);

The result of this script is

1 10 3
6 99 20 

And here is a jsfiddle http://jsfiddle.net/krasimir/bAGVD/3/

Krasimir
  • 13,306
  • 3
  • 40
  • 55
  • You are passing an empty object to `.apply`. As a result, `obj1` and `obj2` won't inherit from `GeneralClass.prototype`. – Felix Kling Aug 26 '13 at 08:29
  • I agree. It depends of how the class is implemented. If all the logic is inside the function then it will work. – Krasimir Aug 26 '13 at 08:33
  • True, but properly structured code uses the prototype I would argue. Still, I think it's important to point it out! – Felix Kling Aug 26 '13 at 08:34
  • Yep. I totally agree with you. Erel Segal Halevi should know about that. I personally prefer revealing module pattern over the prototype, but that's more like a context depending thingy. – Krasimir Aug 26 '13 at 08:48
  • @Krasimir `revealing module` and `prototype` design patterns might look similar in someways, but they're totally different animals. The design pattern you use is totally subjected to what you `need` to do, not what you `prefer`. – Mahdi Aug 26 '13 at 09:00
  • Sorry, I wasn't clear enough. I was talking about inheritance. I know that those two things are completely different, but I found that it is easier for me to avoid the usage of the prototype. It will be interesting for me - what you think about http://krasimirtsonev.com/blog/article/JavaScript-is-cool-modular-programming-extending#extending-modules – Krasimir Aug 26 '13 at 09:57
  • @Krasimir well, I know that it's not a place to talk about the article for example, but anyways, the article is good generally, but I'm not following you at some points. For example the HTML Generator is actually a bad practice in my mind (we have client-side template engines). If you're a serious developer you do think about maintainability of your code, and you always believe that someone else might start working on my code someday. I think it's fine if you really like to code in this way, but for a single developer projects or learning/study projects. – Mahdi Aug 26 '13 at 11:07