views:

374

answers:

8

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
+2  A: 

You can create instances without the new operator (here is a great article written about this by Douglas Crockford http://yuiblog.com/blog/2006/11/13/javascript-we-hardly-new-ya/). But it will not help you with the "instanceof" story.

nemisj
That's not about general purpose `new` use, it's about specific places you can avoid it, such as with `Object` (use `{}` instead), `Array` (use `[]` instead), and especially `Function`.
T.J. Crowder
The question was, if it's possible. The article explains that YES it is possible, and it also covers some aspects why it can be useful.
nemisj
@nemisj: No, it doesn't. It talks about not using `new` inappropriately (like `new function() { ... }`), *not* about avoiding using it in general. The article doesn't talk about inheritance at all, in fact.
T.J. Crowder
@T.J. Crowder: My mistake, haven't noticed the idea behind c instance a :)
nemisj
+7  A: 

What's wrong with using the new keyword?

At any rate, it sounds like the best thing to do is read up on Javascript inheritance: http://javascript.crockford.com/inheritance.html

Matt Ball
Not sure whats wrong with the new Key word. YUI uses it extensively...
Zoidberg
By all means, read Crockford. He's informed and educational. But don't read Crockford as gospel, not least because some of his earlier articles (at least!) promote extremely inefficient programming practices. And I'm not immediately seeing how Crockford's articles on simulating classical inheritance in JavaScript (now regarded by him as a "mistake") relate to the pragmatic question posted by the OP.
T.J. Crowder
http://stackoverflow.com/questions/377716/javascript-automatic-getter-setters-john-resig-book/381025#381025
Andreas Grech
+4  A: 

Someone posted an article by douglas crockford in this question, and it explains exactly what your asking.

http://stackoverflow.com/questions/1809914/oo-javascript-constructor-pattern-neo-classical-vs-prototypal

Zoidberg
What an .... *interesting* approach. And darned if it doesn't do exactly that, get rid of `new` (and `this`). A bit extreme, but shows how powerful the language is.
T.J. Crowder
instanceof wouldn't return the results desired in the question though.
AnthonyWJones
+2  A: 

You can't avoid new in the general case (without going to extremes, as per the Crockford article Zoidberg indirectly linked to) if you want inheritance and instanceof to work, but then (again), why would you want or need to?

The only reason I can think of where you'd want to avoid it is if you're trying to pass a constructor function to another piece of code that doesn't know it's a constructor. In that case, just wrap it up in a factory function:

function b() {
    // ...
}
function makeB() {
    return new b();
}
var c = makeB();
T.J. Crowder
+1  A: 

The simple answer to your specific question is: no.

It would help you identified why you want to avoid new. Perhaps the patterns alluded to by one of the other answers will help. However none of them result in the instanceof returning true in your tests.

The new operation is essentially:-

var x = (function(fn) { var r = {}; fn.call(r); return r;}(b);

However there is the difference that the constructing fn is attached to the object using some internal property (yes you can get it with constructor but setting it doesn't have the same effect). The only way to get instanceof to work as intended is to use the new keyword.

AnthonyWJones
A: 

JavaScript objects can be created without using the new keyword.

For example the following function returns an object without using new keyword


function a(){
    var obj ={};
    obj.name = "hello";
    obj.age = 12;

    return obj;

}
awin
Right, but as AWJ said multiple times already, `instanceof` won't work as the OP wants it to by doing that.
Matt Ball
A: 

The only way to get instanceof to work is to use the new keyword. instanceof exploits __proto__ which is established by new.

Upper Stage
Could I do something with assignment to __proto__ then?
pr1001
Unfortunately, I understand __proto__ is readonly.
Upper Stage
Of course, __proto__ is "underscore underscore proto underscore underscore."
Upper Stage
Yep, stupid formatting. In Rhino and the Chrome debugger, `__proto__` doesn't seem to be read-only.
pr1001
That's good to know; I read somewhere that ____proto____ is deprecated. Might be a difficult tact to pursue given the different appraoches taken by different browsers.
Upper Stage
+2  A: 

You can use this pattern:

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

after which you can do:

var myObj = SomeConstructor();
KooiInc
I just tried this and it looks very promising. Will develop it more later.
pr1001
+1 this is the usual idiom for allowing constructors to work without `new`.
bobince
Comment #1: But...but...but...it still uses `new`. I'm not seeing the point here, it's just a factory method that *also* allows the user to use `new` if they want to. That just leads to some members of the team using `new` and others not; a maintenance nightmare. Support one or the other (e.g., by including debug code you remove for production that throws an exception if the author didn't -- or did -- use `new` to call the constructor), but not both.
T.J. Crowder
Comment #2: If you want to use this pattern, make sure you use a named function (as in your example) and use the function's name, not `arguments.callee` -- e.g.: `if (!(this instanceof SomeConstructor))`. Using `arguments.callee` will slow down your functions *dramatically* (2-10x, depending on the JavaScript engine), and will throw an exception in JavaScript's new "strict" mode.
T.J. Crowder
Sorry, T.J., if I wasn't clear but I was looking for code where the _end user_, not the library creator, avoided using `new`.
pr1001