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
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);