13

I have been reading JavaScript Patterns book by Stoyan Stefanov and one of the patterns to enforcing the new operator for constructor functions goes like this

function Waffle() {
if (!(this instanceof Waffle)) {
return new Waffle();
}
this.tastes = "yummy";
}
Waffle.prototype.wantAnother = true;

when writing this way you can invoke Waffle either one of these ways

var first = new Waffle(),
second = Waffle(); 

I think this is a helpful feature not sure if it's implemented in future versions of ecma/javascript

I came up with something on my own that I thought could just copy and paste each time when creating a constructor function

something like this

function checkInstance (name) {
    if (name.constructor.name === undefined) {
       return "construct it"
    } else {
       return false;
    }
}

function Waffle() {
    var _self = checkInstance.call(this, this);
    if (_self === "construct it") {
       return new Waffle()
    }
    this.tastes = "yummy"
}

var waffle = Waffle()
waffle

Therefore I can invoke Waffle either way new Waffle or Waffle() and still have it return an object

My problem that I'm having is here

  if (_self === "construct it") {
       return new Waffle()
       }

Is there anyway I can refer to new Waffle() without referring to the actual name of the constructor function meaning so I could copy and paste this each time and not have to change anything. Meaning I could I save Waffle() as a variable and do something like

return new var

I wish I could use this.name but that doesn't work either until it is invoked.

I have a feeling I can't but wanted to at least ask some of the people here on stack overflow if it was a possibility

Again your comments and feedback is appreciated

Thalaivar
  • 23,282
  • 5
  • 60
  • 71
James Daly
  • 1,357
  • 16
  • 26
  • Not since `arguments.callee` was deprecated – SLaks Jun 10 '13 at 21:01
  • `name.constructor.name` will never be `undefined`. In the default case, when new isn't used, it will at least be `Window`, but it depends on the value of `this` when you pass it in to checkInstance. – Paul Jun 10 '13 at 21:02
  • 1
    *"I think this is a helpful feature not sure if it's implemented in future versions of ecma/javascript"* not every function is a constructor function, so it doesn't make sense to enforce something like this. If you just meant whether there will be helper functions for this, I don't think so. – Felix Kling Jun 10 '13 at 21:08
  • @Paulpro I don't believe that's the case if you are using ecmascript 5 - I've run this in firebug and doesn't always come out undefined – James Daly Jun 10 '13 at 21:09
  • I said it will ***never*** be undefined, not always. – Paul Jun 10 '13 at 21:09
  • if i run this in firebug it's working function checkInstance (name) { if (name.constructor.name === undefined) { return "construct it" } else { return false; } } function Waffle() { var _self = checkInstance.call(this, this); if (_self === "construct it") { console.log('yes'); return new Waffle() } this.tastes = "yummy" } var waffle = Waffle() waffle – James Daly Jun 10 '13 at 21:14
  • @Paulpro value of `this` can be undefined if called without context or without `new`, if strict mode is used and interpreted. – atondelier Jun 10 '13 at 22:51

7 Answers7

8

I have a better solution. This is what you're currently doing:

function Waffle() {
    if (!(this instanceof Waffle))
        return new Waffle;
    this.tastes = "yummy";
}

Waffle.prototype.wantAnother = true;

This pattern isn't really nice because you're mixing the code to construct a new object with the code to check if the new keyword is being used.

I've mentioned before that you shouldn't use the new keyword in JavaScript as it breaks functional features. Instead let's create another function which does the same thing:

Function.prototype.new = (function () {
    return function () {
        functor.prototype = this.prototype;
        return new functor(this, arguments);
    };

    function functor(constructor, args) {
        return constructor.apply(this, args);
    }
}());

This function allows you to create an instance of a function as follows:

var waffle = Waffle.new();

However we don't want to use new at all. So to do away with it we'll create a function which wraps a constructor as follows:

function constructible(constructor) {
    function functor() { return Function.new.apply(constructor, arguments); }
    functor.prototype = constructor.prototype;
    return functor;
}

Now we can define the Waffle function as follows:

var Waffle = constructible(function () {
    this.tastes = "yummy";
});

Waffle.prototype.wantAnother = true;

Now you can create objects with or without using new:

var first = new Waffle;
var second = Waffle();

Note: The constructible function is pretty slow. Use the following version of constructible instead - it's a little faster:

function constructible(constructor) {
    constructor = Function.bind.bind(constructor, null);
    function functor() { return new (constructor.apply(null, arguments)); }
    functor.prototype = constructor.prototype;
    return functor;
}

Personally I wouldn't use either of these two methods. I would just remember to write new, or (more likely) I would restructure my code as follows:

var waffle = {
    create: function () {
        var waffle = Object.create(this);
        waffle.tastes = "yummy";
        return waffle;
    },
    wantAnother: true
};

var first = waffle.create();
var second = waffle.create();

If you want to know more about this pattern then read the following answer: https://stackoverflow.com/a/17008403/783743

Community
  • 1
  • 1
Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • You are right that having to write code for this with *inside* a *constructor* function is stupid so +1 for that. – Esailija Jun 11 '13 at 09:19
  • Thanks Aadit - I do believe you provided the best answer and I enjoyed your article. I prefer using object literals myself. and usually use crockford's createObj function for inheritance – James Daly Jun 11 '13 at 21:40
  • `instanceof` check is fine, compared to the other voodoo magic you need to write to avoid it. The only difference is that I would do a throw, if **new** was not used, to enforce code base consistency. I was going to post this as an answer, but found existing and upvoted: http://stackoverflow.com/a/17035925/897326 – Victor Zakharov Oct 14 '16 at 21:51
3

You could use something like this:

var Waffle = (function() {
    function Waffle() {
        this.tastes = "yummy"
    }

    return exportCtor( Waffle );
})();


var waffle = Waffle();

alert(waffle.tastes);

console.log(Waffle);

/*
function ConstructorProxy() {
    "use strict";
    return new Constructor();
}
*/

http://jsfiddle.net/ywQJF/

It handles variable arguments too

Esailija
  • 138,174
  • 23
  • 272
  • 326
  • @Paulpro It's the function I made that is too long to copypaste here, it's in the linked jsfiddle though. – Esailija Jun 10 '13 at 21:07
  • @Esailija - Why is your `exportCtor` function so big? Look at my `constructible` function. It does pretty much the same thing your function does: http://jsfiddle.net/ywQJF/1/ – Aadit M Shah Jun 11 '13 at 12:35
  • @AaditMShah First of all, because [it's optimized as ****](http://jsperf.com/i-hate-jsperf-titles). Secondly you can monkey patch/add methods to the underlying prototype through the proxy and it also copies over static properties too. So for example these work: `var Date2 = exportCtor(Date); Date2.now(); Date2.prototype.getLol = "lol"; //Affects Date.prototype`. – Esailija Jun 11 '13 at 12:46
  • @Esailija - Is it really worth writing so many lines of code for such a pathetic design pattern? Yes it's optimized but I would never use such ugly code in any of my projects (readability, understandability and maintainability is important). Hell, I would never even __need__ to use such code in any of my projects because I would simply remember to write `new` instead of being such a fussy b******. Do you usually program in C? – Aadit M Shah Jun 11 '13 at 12:53
  • 1
    @AaditMShah It's not project code but general purpose library function. As such, performance is important because while you might be doing an app with 5 users that does form validation, others might be doing games and other performance sensitive apps and ideally they all should be able to use the same general purpose libraries to some extent. – Esailija Jun 11 '13 at 12:59
  • 1
    @Esailija - Lol. If you made it available as a library function and if I used your library then I wouldn't even bother checking the source. If I compared the speeds between my handcrafted function and yours then I would wonder how does your pattern manage to execute so fast. – Aadit M Shah Jun 11 '13 at 13:05
3

arguments.callee, which refers to the current function, is the most simple solution. It's is deprecated, though, so use it at your own risk.

function Waffle() {
    if (!(this instanceof arguments.callee))
        return new arguments.callee();

    this.tastes = 'yummy';
}

It's a hard problem also because you probably want to preserve the arguments you're passing, as Vinothbabu mentioned. But if you real intention is enforcing new, you could simply throw an error, which is a simple two lines of code:

if (!(this instanceof Waffle))
    throw new Error('Constructor called without new');

You could even wrap it in a function:

function cons(C) {
    var c = function () {
        if (!(this instanceof c))
            throw new Error('Constructor called without new');

        C.apply(this, arguments);
    };
    c.prototype = C.prototype;
    return c;
}

var Waffle = cons(function () {
    this.tastes = 'yummy';
});
Waffle.prototype.wantAnother = function () {
    return true;
};

new Waffle(); // { tastes: 'yummy', 'wantAnother': true }
Waffle(); // throws error

Now Waffle must be called with new -- otherwise, it throws an error.

Casey Chu
  • 25,069
  • 10
  • 40
  • 59
  • Hi Casey, thanks for your answer - I should have mentioned that I was looking for something other than arguments.callee() since it's deprecated. I would like to do something similar to what you did with that cons function but I'd like to have the ability to call the constructor function w/o the new prefix all the time – James Daly Jun 11 '13 at 02:26
2

There is simpler way how to enforce creation of new object even without new:

function Waffle() {
    return {tastes:"yummy"};
}

var a = Waffle();
var b = new Waffle();

alert(a.tastes); // yummy
alert(b.tastes); // yummy

Explanation

Using new with function, there are two possibilities:

  • the function returns object: the object is the result of the new function() expression
  • the function doesn't return object: the function itself with new context is returned

See the ECMA script documentation

Workaround: prototype and arguments

function Waffle(taste,how) {
    return {
        tastes: taste+" "+how,
        __proto__: Waffle.prototype
    }
}
Waffle.prototype.wantmore = "yes";

var a = Waffle("yummy","much");
var b = new Waffle("gummy","little");

console.log(a.tastes,b.tastes); // yummy much, gummy little
console.log(a.wantmore,b.wantmore); // yes, yes

This deserves a fiddle.

Note: constructor.name (which you used in your pattern) is not standard

Note 2: __proto__ is also not standard, but is supported by modern browsers and will be standardized in ES6.

Jan Turoň
  • 31,451
  • 23
  • 125
  • 169
  • Hi Jan - I use this implementation often the only problem is that you can't prototype Waffle meaning Waffle.prototype.wantmore = true Waffle is unaware of wantmore – James Daly Jun 11 '13 at 02:07
  • @JamesDaly see my update: it also solves the issue with constructor arguments. – Jan Turoň Jun 11 '13 at 02:42
  • very nice implementation - you got my upvote. Still trying to decide which one to mark as the correct answer as they are all pretty good - but I liked yours very much because it's short, concise and relatively easy to comprehend – James Daly Jun 11 '13 at 03:01
  • constructor.name might not be standard but I believe it works in all the browsers as does function doSomething() { } alert(doSomething.name); – James Daly Jun 11 '13 at 03:03
  • The prototype fix is even worse than what you first had and defeats the whole point of prototypes on pretty much all accounts. – Esailija Jun 11 '13 at 08:51
  • @Esailija would you please enlighten us in some constructive way? – Jan Turoň Jun 11 '13 at 09:02
  • @JanTuroň no obvious way how inheritance would work and creating a new constructor function and a closure everytime you need an instance. – Esailija Jun 11 '13 at 09:11
  • @Esailija - calling everytime - of course, the OP asked for pattern, not for proxy constructor. My solution is native and easily customizable. And if customization is very variable (which is this case), the pattern should be preferred over any wrapper function due to accidental complexity. – Jan Turoň Jun 11 '13 at 09:48
  • I'm not sure what you mean by native, [dirty, native](http://www.youtube.com/watch?v=9mXe9nRiPHI) ? – Esailija Jun 11 '13 at 09:50
  • @Esailija `x.prototype = Waffle.prototype` - there is no benefit for writing proxy function for this, it can't be simplier. If you need arguments, you add the bind part. But if you don't need them, you omit them: this keeps the code simple without any additional abstraction. By native I mean without need of any extra code, it is pattern which is about attitude. The video you posted is about design: two different things. (But yea, it's funny, especially the final part. And these comments are fruitful, too.) – Jan Turoň Jun 11 '13 at 10:08
  • @AaditMShah no problem, thank you for your rather less polite, but constructive comment. I was very tired yesterday. I believe we neither need binding the `x` object, nor the wrapper function, since `x` is in `Waffle` scope and has access its params. Is it better after the update? – Jan Turoň Jun 11 '13 at 13:02
  • @AaditMShah ...and you are partially artist, right? I'm not sure if I get your tale about the straw and the soup right, but I further improved the code at the very end of my answer. Is it better now, maestro? – Jan Turoň Jun 11 '13 at 13:30
2

The best approach, in my opinion, is not to enable yourself to invoke things incorrectly:

function Waffle() {
  if (!(this instanceof Waffle)) {
    throw "Waffles need to be fresh or they're gross. Use 'new'.";
  }
}

But, if you simply must enable yourself to write inconsistent code, make initialization a separate step.

function Waffle(options) {
  var o = options || {};
  if (this instanceof Waffle) {
    this.init = function() {
      /* this is really your constructor */
      console.log("initializing ... ");
    }

    if (!o.__do_not_initialize) {
      this.init(arguments);
    }
  } else {
    var rv = new Waffle( { __do_not_initialize: true } );
    rv.init(arguments);
    return rv;
  }
}

If you want to force consistency the other way -- never using the new keyword, create a builder function:

function BuildWaffle(options) {
  var o = options || {};

  if (this instanceof WaffleBuilder) {
    throw "BuildWaffle cannot be instantiated.";
  }

  var Waffle = function Waffle() { /* whatever */ }
  Waffle.prototype.doStuff = function() { /* whatever else */ }

  var rv = new Waffle(options);
  return rv;
}
svidgen
  • 13,744
  • 4
  • 33
  • 58
  • What you might interpret as inconsistent code might be consistent for others - it's all in the interpretation. I think the new prefix "obscures the nature's true prototypal nature" as crockfod would say so I'm thinking of ways of using new within the constructor function instead of invoking it with the new prefix - just a matter of experimenting and taste I believe. that's the beauty of javascript – James Daly Jun 11 '13 at 03:16
  • just looking for a somewhat simple solution that I could cut and paste for each constructor function so it can be invoked either way without actually referring to the word Waffle – James Daly Jun 11 '13 at 03:18
  • 1
    @JamesDaly Whether the `new` keyword is "good" is irrelevant. Using `new` in some places and not others is inconsistent by definition. If you plan on *never* using the `new` keyword but *need* the returned object to be a `Waffle`, create a `BuildWaffle()` function that leverages a "private class." (Edits pending ... ) – svidgen Jun 11 '13 at 03:29
  • @JamesDaly If you truly believe that `new` obscures the true nature of prototypal inheritance then __stop using the constructor pattern__. That's what Crockford meant when he said that the `new` keyword obscures the true nature of prototypal inheritance. You should read this blog post: [why prototypal inheritance matters](http://aaditmshah.github.io/why-prototypal-inheritance-matters "Aadit M Shah | Why Prototypal Inheritance Matters"). There are 2 patterns of prototypal inheritance - the prototypal pattern and the constructor pattern. Read more here: http://stackoverflow.com/a/17008403/783743 – Aadit M Shah Jun 11 '13 at 12:18
  • @Aadit - I read your blog post and I agree with it, most of the time I use the modular or revealing modular pattern using object literals I find them extremely easy to work with but if you want to use inheritance and you are unable to use Object.create which most people aren't because they have to support IE 8 still then you use the createObject function that Crockford originally created which still had to use the keyword new in the function - it returned new F(). I don't normally use constructor functions but I like to learn different design patterns at least to understand them. – James Daly Jun 11 '13 at 20:34
  • Referenced your answer from the accepted one. I really like the `throw` idea better than providing syntax sugar for developers. Make it right, or it will blow up. It's also simple to read and understand, even for non-JS gurus, compared to other walls of code posted here. – Victor Zakharov Oct 14 '16 at 21:53
1
if (!(this instanceof Waffle)) {
    return new Waffle();
}

This has two problems...

  1. one that it won 't work in an anonymous function which has no name
  2. it loses all arguments sent to the constructor.

Using a more generic approach might look something more like this:

if (!instanceExists(this, arguments)) {
    return requireInstance(this, arguments);
}

This approach ensures that the constructor is called with new, without having to state the function' s name, andadds all arguments sent to the constuctor so they aren 't lost during the process.

Here 's the full code for the above:

Function.prototype.callNew = function (args) {
    var a = [];
    for (var i = 0; i < args.length; i++) a.push("a[" + i + "]");
    var fn = new Function("var a=arguments;return new this(" + a.join(",") + ");");
    return fn.apply(this, args);
}

function instanceExists(t, args) {
    if (t instanceof args.callee) {
        return true;
    } else {
        return false;
    }
}

function requireInstance(t, args) {
    var fn = args.callee;
    if (!instanceExists(t, args)) {
        return fn.callNew(args);
    }
}

function Waffle(one, two, three) {
    if (!instanceExists(this, arguments)) {
        return requireInstance(this, arguments);
    }
    this.one = one;
    this.two = two;
    this.three = three;
}

Waffle.prototype.serve = function () {
    var out = [];
    for (var j in this) {
        if (!this.hasOwnProperty(j)) continue;
        out.push(j + ': ' + this[j]);
    }
    return ' {
    ' + out.join(",\n") + '
}
';
}

A fiddle for you to play with. http://jsfiddle.net/RkPpH/

var waffle = Waffle(1, 2, 3);
alert(waffle.serve());
Thalaivar
  • 23,282
  • 5
  • 60
  • 71
  • You are dynamically evaluating code every time someone creates an instance without using `new`. – Esailija Jun 11 '13 at 09:02
  • @Esailija: It is necessary because apply/call don't work in conjunction with the new operator. Unless you use one of the other approaches such as extending a new object with prototype. – Thalaivar Jun 11 '13 at 10:09
  • Well you can just generate the code once. Not every time you create an instance. – Esailija Jun 11 '13 at 10:29
  • @Vinothbabu - Yes, the `new` operator is a bitch. You should ready my answer. I created a new version of `new` (sorry for the pun) which _can_ be used in conjunction with `apply`. In addition you may find my blog post on [why prototypal inheritance matters](http://aaditmshah.github.io/why-prototypal-inheritance-matters "Aadit M Shah | Why Prototypal Inheritance Matters") to be interesting. – Aadit M Shah Jun 11 '13 at 11:29
  • @Vinothbabu - No offense, but you're code is really bad. Hence -1. – Aadit M Shah Jun 11 '13 at 11:37
0

I didn't get a sense of whether this was client or server-side, but a pattern I use sometimes goes as follows. I use this in Node but have attempted to make it a possible client-side solution as well - the Node-specific stuff is commented out but there for reference depending on your environment.

First, I create something to be used along the lines of a traditional OO base or super class like so:

//// Node:
//module.exports.Base = Base;

function Base(opts) {
    var self = this;
    if (!(self instanceof Base)) return new Base(opts);
    self.opts = opts || {};
}

Upon which you can define your methods, in usual the fashion. You can even manually throw if the method should be provided by subclasses implementing something like abstract:

// commonMethod is available to subclasses:
Base.prototype.commonMethod = function () {
    var self = this;
    //access self.opts to get the constructor arguments.
    //makes self always point to the right object.
}

// Provide abstractMethod, but subclass is responsible for implementation:
Base.prototype.abstractMethod = function () {
    //or throw an error if this should be implemented by subclasses:
    throw new Error('implement me');
}

Now you can do this:

//// If using Node:
//var inherits = require('util').inherits;
//var Parent = require('./Base').Base;

function Sub (opts) {
    var self = this;
    //// If using node and you  want super_ to be called prior to creating a new Sub:
    //if(Sub.super_) Sub.super_.call(this, opts);

    // Always do this:
    if (!(self instanceof Sub)) return new Sub(opts);

    //// If using node and you are ok with super_ called after creating new Sub:
    //if(Sub.super_) Sub.super_.call(this, opts);
    //// otherwise:
    parent(opts);
}

//// If using Node:
//inherits(Sub, Base);
//// Otherwise:
Sub.prototype.constructor = Base;
Sub.prototype.parent = Base.prototype;

//and provide the implementation of abstractMethod:
Sub.prototype.abstractMethod() {
    //...
}

And to formally answer the specific question, all of the

if (!(self instanceof Sub)) return new Sub(opts);

is where you get the guaranteed new situation.

Matt Mullens
  • 2,266
  • 15
  • 14