2

I want to create an instance of a Point with and without the new operator like:

Point(5, 10); // returns { x: 5, y: 10 }
// or
new Point(5, 10); // also returns { x: 5, y: 10 }

I got it working so far with the help of StackOverflow.

function Point() {
  if (!(this instanceof Point)) {
    var args = Array.prototype.slice.call(arguments);
    // bring in the context, needed for apply
    args.unshift(null);
    return new (Point.bind.apply(Point, args));
  }
  // determine X and Y values
  var pos = XY(Array.prototype.slice.call(arguments));
  this.x = pos.x;
  this.y = pos.y;
}

But that looks horrible, I am even unshifting null into the array so I can use apply. That just doesn't feel right.

I found a lot of solutions how to achieve it with new constructors and constructor wrappers but I want to keep it as simple as possible (it's just a plain, simple Point).

Is there an easier way to achieve this behaviour?

Community
  • 1
  • 1
dan-lee
  • 14,365
  • 5
  • 52
  • 77
  • Will this have to be for all functions or just 1? If just 1, quite frankly it'd be better to rewrite that function. – Qantas 94 Heavy Jun 12 '13 at 10:52
  • @Qantas94Heavy It's just the `Point` function which I want to behave like this. But of course it's called multiple times. – dan-lee Jun 12 '13 at 10:53

1 Answers1

3

If you don't mind using ECMAScript 5 functions, Object.create() could help:

function Point()
{   var args = Array.prototype.slice.call(arguments);
    if (this instanceof Point) return Point.apply(null, args);
    var pos = XY(args); 
    var result = Object.create(Point.prototype);
    result.x = pos.x;
    result.y = pos.y;
    return result;
}

If you need ECMAScript 3 compatibility, this crazy, convoluted solution is yet another one (note that it's just a wrapper for an internal equivalent of new Point):

function Point() 
{   var pos = XY(Array.prototype.slice.call(arguments));
    function internalPoint()
    {   this.x = pos.x;
        this.y = pos.y;
    }
    internalPoint.prototype = Point.prototype;
    return new internalPoint;
}
Qantas 94 Heavy
  • 15,750
  • 31
  • 68
  • 83
  • Ugh! I think I am going with ECMAScript5. – dan-lee Jun 12 '13 at 12:21
  • 1
    @DanLee: note that the first method won't be supported by IE8 and below , unless you add a shim for `Object.create()`. Having said that, I'd agree that the second one is crazy, but less crazy than the one you made :O. – Qantas 94 Heavy Jun 12 '13 at 12:25
  • Haha, yeah it was puzzled together :) I am trying to get my head around these structures. – dan-lee Jun 12 '13 at 12:41