Search code examples
javascriptinheritanceprototypeconstructor

Can I construct a JavaScript object without using the new keyword?


Here is what I'd like to do:

function a() {
  // ...
}
function b() {
  //  Some magic, return a new object.
}
var c = b();

c instanceof b // -> true
c instanceof a // -> true
b instanceof a // -> true

Is it possible? I can make b be an instance of a easily by hooking a into its prototype chain but then I have to do new b(), which is what I'm trying to avoid. Is what I want possible?

Update: I feel that it might be possible with judicious use of b.__proto__ = a.prototype. I'm going to experiment more after work.

Update 2: Below is what seems to be the closest you can get, which is good enough for me. Thanks all for the interesting answers.

function a() {
  // ...
}
function b() {
  if (!(this instanceof arguments.callee)) {
    return new arguments.callee();
  }
}
b.__proto__ = a.prototype

var c = b();
c instanceof b // -> true
c instanceof a // -> false
b instanceof a // -> true

Update 3: I found exactly what I wanted in a blog post on 'power constructors', once I added the essential b.__proto__ = a.prototype line:

var object = (function() {
     function F() {}
     return function(o) {
         F.prototype = o;
         return new F();
     };
})();

function a(proto) {
  var p = object(proto || a.prototype);
  return p;
}

function b(proto) {
  var g = object(a(proto || b.prototype));
  return g;
}
b.prototype = object(a.prototype);
b.__proto__ = a.prototype;

var c = b();
c instanceof b // -> true
c instanceof a // -> true
b instanceof a // -> true
a() instanceof a // -> true

Solution

  • You can use this pattern:

    function SomeConstructor(){
       if (!(this instanceof SomeConstructor)){
            return new SomeConstructor();
       }
       //the constructor properties and methods here
    }
    

    after which you can do:

    var myObj = SomeConstructor();
    

    [Edit 2023 (actually: re-edit)] To avoid the new keyword altoghether you may use a factory function. Here's an example. It's what Douglas Crockford calls a class free object oriented solution.

    The pattern/idea is used in (among other) this small github repository

    const Person = (name = 'unknown', age = 0, male = false) => {
      const value = () => `This is ${name}. ${
        !male ? `Her` : `His`} age is ${age} years.`;
        
      return {
        get whoIs() { return value(); },
        toString() { return value(); },
        addAge: years => age += years,
        setAge: newAge => age = newAge,
        rename: newName => name = newName,
      };
    }
    // usage
    const [ jane, charles, mary ] =  [
      Person(`Jane`, 23), 
      Person(`Charles`, 32, 1), 
      Person(`Mary`, 16), ];
    
    jane.addAge(17);
    charles.setAge(76);
    console.log(`${jane}`);
    console.log(`${mary}`);
    console.log(charles.whoIs);