Reputation: 28528
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 ?
Upvotes: 5
Views: 2521
Reputation: 122986
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
Upvotes: 1
Reputation: 169511
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".
Upvotes: 1
Reputation: 204
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.
Upvotes: 0
Reputation: 339985
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.
Upvotes: 1