4
function drawLine(ctx, sX, sY, eX, eY, sRGB, fRGB, lWidth, capStyle)
{
    ctx.beginPath();
    ctx.moveTo(sX, sY);
    ctx.lineTo(eX, eY);
    ctx.lineWidth = lWidth||5;
    ctx.strokeStyle = 'rgb(49, 129, 48)';
    ctx.lineCap = 'round';
    ctx.stroke();
    ctx.closePath();
}

And then I want to call the function like this:

drawLine(ctx, 50, 50, 100, 100, someStrokeStyle, someFillStyle, someCapStyle);

As you can see I have skipped the lWidth parameter. I want the function to still work, even when the lWidth is not passed as a parameter. How will I do this? Atm, it might think that the someCapStyle is the lwidth.

Joe Slater
  • 2,483
  • 6
  • 32
  • 49
  • you missed one parameter in the arguments thats what i see. How can i know thats lWidth parameter – 999k Mar 19 '13 at 11:07
  • @555k yes exactly, how would the function still work when I chose not to give in a parameter. – Joe Slater Mar 19 '13 at 11:07
  • You are not using arguments fRGB and capStyle. So if you miss one, then function will get called with capStyle=undefined. your lWidth value will be someCapStyle – 999k Mar 19 '13 at 11:10
  • @555k Yes and how would I manage to tell the function that I want a default value for lWidth and someCapStyle for capStyle – Joe Slater Mar 19 '13 at 11:11
  • if you want the function to work with lWidth as an optional parameter make it the last argument in function prototype – 999k Mar 19 '13 at 11:12
  • @555k But I am going to call this function many times. Sometimes, I will not specify lWidth, other times I will not specify capStyle. – Joe Slater Mar 19 '13 at 11:13
  • then better use objects.. see below answers. i think there is no other solution – 999k Mar 19 '13 at 11:15
  • @555k - There is another solution - specialization. Read about [The Three Projections of Doctor Futamura](http://blog.sigfpe.com/2009/05/three-projections-of-doctor-futamura.html "A Neighborhood of Infinity: The Three Projections of Doctor Futamura"). Someone has already written a JavaScript library to help you with it. It's called [Jeene](http://blog.higher-order.net/2008/09/14/jeene/ "Jeene: An automatic partial evaluator for JavaScript | Higher-Order"). – Aadit M Shah Mar 19 '13 at 11:30

5 Answers5

3

When you have a big amount of arguments to pass into a function like you have, use an object:

function foo({param1: val1, parma2: val2}) {}

In that case you wont be depend on number of arguments and order of them being represented.

So you can rewrite your function:

 function drawLine(drawObj)
{
    ctx.beginPath();
    ctx.moveTo(drawObj.sX, drawObj.sY);
    ctx.lineTo(drawObj.eX, drawObj.eY);
    ctx.lineWidth = drawObj.lWidth||5;
    ctx.strokeStyle = drawObj.sRGB;
    ctx.lineCap = drawObj.capStyle;
    ctx.stroke();
    ctx.closePath();
}
happyCoda
  • 418
  • 2
  • 2
2

When you don't pass any argument, undefined value is passed instead, so just check in the function whether the argument has been passed or not:

if(typeof argument == "undefined") 
{ 
   argument = "default value";
}

So to not pass lWidth, just pass undefined as its value

P.S. the best way is to use a single argument args, which will be object containing all current parameters as properties.

999k
  • 6,257
  • 2
  • 29
  • 32
artahian
  • 2,093
  • 14
  • 17
  • Is there a way to just skip it completely, not even specify undefined? – Joe Slater Mar 19 '13 at 11:15
  • @AnkurSharma yes. use if(argument) – 999k Mar 19 '13 at 11:19
  • @555k But it will think that the lWidth is defined, and capStyle is not defined. You see what I mean? Anyway, its ok, I will just use an object as shown by other answerers. Thanks for answering. – Joe Slater Mar 19 '13 at 11:23
  • @AnkurSharma you can always test by yourself how javascript handles arguments: http://jsfiddle.net/BKkUE/. And to add to this answer read about undefined/null at http://stackoverflow.com/questions/801032/why-is-null-an-object-and-whats-the-difference-compared-to-undefined – apelsinapa Mar 19 '13 at 11:28
2

What you want is to partially evaluate the drawLine function, assigning a constant value to lWidth. There's a JavaScript library called Jeene that does just this. This is how you would use it:

function drawLine(ctx, sX, sY, eX, eY, sRGB, fRGB, lWidth, capStyle) {
    ctx.beginPath();
    ctx.moveTo(sX, sY);
    ctx.lineTo(eX, eY);
    ctx.lineWidth = lWidth || 5;
    ctx.strokeStyle = "rgb(49, 129, 48)";
    ctx.lineCap = "round";
    ctx.stroke();
    ctx.closePath();
}

Function.prototype.specialize = net.higherorder.jeene.Jeene.make();

var drawLine2 = drawLine.specialize({
    lWidth: null // or whatever value you want
});

Then you use drawLine2 as follows:

drawLine2(ctx, 50, 50, 100, 100, someStrokeStyle, someFillStyle, someCapStyle);

This is called specialization and is a very useful pattern. Read more about it: A Neighborhood of Infinity: The Three Projections of Doctor Futamura

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • Will the function automatically know if someCapStyle is a capStyle and not lWidth. – Joe Slater Mar 19 '13 at 11:29
  • @AnkurSharma - Yes, it will indeed. That's the really cool thing about specialization. Read the blog post to know exactly what's happening: http://blog.higher-order.net/2008/09/14/jeene/ – Aadit M Shah Mar 19 '13 at 11:31
  • What if both the arguments are string type? How would function know which one is correct? Could you explain in simple words? I am a newbie, sry about that. – Joe Slater Mar 19 '13 at 11:37
  • @AnkurSharma - Specialization means that the name of the parameter is replaced by the value. Hence it won't confuse `lWidth` and `capStyle`. It's a form of partial evaluation. It's too much too explain in one comment. You should read it for yourself: http://en.wikipedia.org/wiki/Partial_evaluation – Aadit M Shah Mar 19 '13 at 13:06
1

You can put the optional parameter at the end of the paramter list. That way, if you leave it out, the other parameters won't be affected.

Another option would be to pass a single object with the attributes you want to define e.g.

function drawLine(options) {
    options.ctx.beginPath();
    options.ctx.moveTo(options.sX, options.sY);
    options.ctx.lineTo(options.eX, options.eY);
    // etc.
 }
Natrium
  • 30,772
  • 17
  • 59
  • 73
SteveP
  • 18,840
  • 9
  • 47
  • 60
1

You can not use "function overloading" in Javascript, but here is a way to achieve what you want:

How to overload functions in javascript?

Community
  • 1
  • 1
Natrium
  • 30,772
  • 17
  • 59
  • 73