5

Since it is not possible to use new operator with an arguments array (.call or .apply), Then I wondering if I can do it by hand.

In the following code, are obj1 and obj2 equivalent (in ES3) ?

function MyClass(a, b, c) {}

var obj1 = new MyClass(2,3,4)

var tmp = function() {}
tmp.prototype = MyClass.prototype;
var obj2 = new tmp;
obj2.constructor = MyClass;
MyClass.call(obj2, 2,3,4);

- edit1 -

Does your answers mean that the above code is wrong or is not equivalent to an object construction ?

1
  • there is no ES4 you want ES3. ES4 is abandoned. Commented Apr 6, 2011 at 17:10

4 Answers 4

1

Using the following syntax, you should be able to apply/call a constructor directly without too much fuzz. Or instantiate it without using the new operator for that matter.

function MyClass(a,b,c){
  if (!(this instanceof MyClass)){
    return new MyClass(a,b,c)
  }
  // to demonstrate the arguments are usable using call/apply
  this.arg1 = a;
  this.arg2 = b;
  this.arg3 = c;
}

var obj2 = MyClass.call(null,1,2,3); // or MyClass.apply(null,[1,2,3])
alert([obj2.arg1,obj2.arg2,obj2.arg3].join(',')); //=> 1,2,3 
Sign up to request clarification or add additional context in comments.

Comments

1

If you're using ES5 you can do this properly with Object.create():

function MyClass(a) {
    console.log('in constructor with param: ' + a);
    this.foo = a;
}

var a = new MyClass('a');

var b = Object.create(MyClass.prototype);
b.constructor.apply(b, ['b']);

console.log('a.foo = ', a.foo, ', b.foo = ', b.foo);
console.log(b instanceof MyClass);

output:

in constructor with param: a
in constructor with param: b
a.foo =  a , b.foo =  b
true

See http://jsfiddle.net/Qjfyt/1/, which shows the constructor only being called once, as expected.

1 Comment

Right, Object.create is actually the solution for ES5. I have just modified the question to make it clear. Thanks.
1

What about this :

var o = new MyClass;
MyClass.apply(o, args);

Your creating an object which inherits from the prototype properly through the new keyword then your calling the constructor again on that object with your parameters.

All this requires is that your constructor is well formed, doesn't crash on null parameters and doesn't have side effects when called more then once on the same object. Of course all these conditions are true because you write proper units, right?

To answer your actual question if you add

tmp.prototype.constructor = MyClass

then yes obj1 and obj2 are "the same".

2 Comments

Thanks for the suggestion, but calling the constructor twice could be a bad idea.
@Soubok yes. Your constructor has to be well written, cheap and must not have side effects
0

Well, you can use apply and get an object that is almost exactly like one instantiated with new like this:

function MyClass(a, b, c) {this.foo = a;}
var a, b = {}, args = [2, 3, 4]; // notice that b is an Object!
a = new MyClass(2,3,4);
MyClass.prototype.constructor.apply(b, [2, 3, 4]);
console.log('a.foo', a.foo, 'b.foo', b.foo);

As you'll see, those are equivalent, but if you check further:

console.log('b.constructor === a.constructor', b.constructor === a.constructor);

They don't have the same constructor. This is because b was originally an instance of "Object" since it was set to an object literal, and it was used as the context of the apply to the MyClass prototype's constructor. They will have the same attributes/methods, so maybe that's good enough for your needs?

EDIT: See @Raynos' comment below. This technique means you lose out on everything defined using the MyClass.prototype.

1 Comment

your b object has none of the methods/properties defined on the prototype

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.