Javascript 1.9.3 / ECMAScript 5 introduces Object.create, which Douglas Crockford amongst others has been advocating for a long time. How do I replace new in the code below with Object.create?
var UserA = function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
}
UserA.prototype.sayHello = function() {
console.log('Hello '+ this.name);
}
var bob = new UserA('bob');
bob.sayHello();
(Assume MY_GLOBAL.nextId exists).
The best I can come up with is:
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB);
bob.init('Bob');
bob.sayHello();
There doesn't seem to be any advantage, so I think I'm not getting it. I'm probably being too neo-classical. How should I use Object.create to create user 'bob'?
With only one level of inheritance, your example may not let you see the real benefits of Object.create.
This methods allows you to easily implement differential inheritance, where objects can directly inherit from other objects.
On your userB example, I don't think that your init method should be public or even exist, if you call again this method on an existing object instance, the id and name properties will change.
Object.create lets you initialize object properties using its second argument, e.g.:
var userB = {
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB, {
'id' : {
value: MY_GLOBAL.nextId(),
enumerable:true // writable:false, configurable(deletable):false by default
},
'name': {
value: 'Bob',
enumerable: true
}
});
As you can see, the properties can be initialized on the second argument of Object.create, with an object literal using a syntax similar to the used by the Object.defineProperties and Object.defineProperty methods.
It lets you set the property attributes (enumerable, writable, or configurable), which can be really useful.
There is really no advantage in using Object.create(...) over new object.
Those advocating this method generally state rather ambiguous advantages: "scalability", or "more natural to JavaScript" etc.
However, I have yet to see a concrete example that shows that Object.create has any advantages over using new. On the contrary there are known problems with it. Sam Elsamman describes what happens when there are nested objects and Object.create(...) is used:
var Animal = {
traits: {},
}
var lion = Object.create(Animal);
lion.traits.legs = 4;
var bird = Object.create(Animal);
bird.traits.legs = 2;
alert(lion.traits.legs) // shows 2!!!
This occurs because Object.create(...) advocates a practice where data is used to create new objects; here the Animal datum becomes part of the prototype of lion and bird, and causes problems as it is shared. When using new the prototypal inheritance is explicit:
function Animal() {
this.traits = {};
}
function Lion() { }
Lion.prototype = new Animal();
function Bird() { }
Bird.prototype = new Animal();
var lion = new Lion();
lion.traits.legs = 4;
var bird = new Bird();
bird.traits.legs = 2;
alert(lion.traits.legs) // now shows 4
Regarding, the optional property attributes that are passed into Object.create(...), these can be added using Object.defineProperties(...).
Object.create is not yet standard on several browsers, for example IE8, Opera v11.5, Konq 4.3 do not have it. You can use Douglas Crockford's version of Object.create for those browsers but this doesn't include the second 'initialisation object' parameter used in CMS's answer.
For cross browser code one way to get object initialisation in the meantime is to customise Crockford's Object.create. Here is one method:-
Object.build = function(o) {
var initArgs = Array.prototype.slice.call(arguments,1)
function F() {
if((typeof o.init === 'function') && initArgs.length) {
o.init.apply(this,initArgs)
}
}
F.prototype = o
return new F()
}
This maintains Crockford prototypal inheritance, and also checks for any init method in the object, then runs it with your parameter(s), like say new man('John','Smith'). Your code then becomes:-
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}} // For example
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.build(userB, 'Bob'); // Different from your code
bob.sayHello();
So bob inherits the sayHello method and now has own properties id=1 and name='Bob'. These properties are both writable and enumerable of course. This is also a much simpler way to initialise than for ECMA Object.create especially if you aren't concerned about the writable, enumerable and configurable attributes.
For initialisation without an init method the following Crockford mod could be used:-
Object.gen = function(o) {
var makeArgs = arguments
function F() {
var prop, i=1, arg, val
for(prop in o) {
if(!o.hasOwnProperty(prop)) continue
val = o[prop]
arg = makeArgs[i++]
if(typeof arg === 'undefined') break
this[prop] = arg
}
}
F.prototype = o
return new F()
}
This fills the userB own properties, in the order they are defined, using the Object.gen parameters from left to right after the userB parameter. It uses the for(prop in o) loop so, by ECMA standards, the order of property enumeration cannot be guaranteed the same as the order of property definition. However, several code examples tested on (4) major browsers show they are the same, provided the hasOwnProperty filter is used, and sometimes even if not.
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}}; // For example
var userB = {
name: null,
id: null,
sayHello: function() {
console.log('Hello '+ this.name);
}
}
var bob = Object.gen(userB, 'Bob', MY_GLOBAL.nextId());
Somewhat simpler I would say than Object.build since userB does not need an init method. Also userB is not specifically a constructor but looks like a normal singleton object. So with this method you can construct and initialise from normal plain objects.
TL;DR:
new Computer() will invoke the constructor function Computer(){} for one time, while Object.create(Computer.prototype) won't.
All the advantages are based on this point.
Sidenote about performance: Constructor invoking like new Computer() is heavily optimized by the engine, so it may be even faster than Object.create.
You could make the init method return this, and then chain the calls together, like this:
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
return this;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB).init('Bob');
Another possible usage of Object.create is to clone immutable objects in a cheap and effective way.
var anObj = {
a: "test",
b: "jest"
};
var bObj = Object.create(anObj);
bObj.b = "gone"; // replace an existing (by masking prototype)
bObj.c = "brand"; // add a new to demonstrate it is actually a new obj
// now bObj is {a: test, b: gone, c: brand}
Notes: The above snippet creates a clone of an source object (aka not a reference, as in cObj = aObj). It benefits over the copy-properties method (see 1), in that it does not copy object member properties. Rather it creates another -destination- object with it's prototype set on the source object. Moreover when properties are modified on the dest object, they are created "on the fly", masking the prototype's (src's) properties.This constitutes a fast an effective way of cloning immutable objects.
The caveat here is that this applies to source objects that should not be modified after creation (immutable). If the source object is modified after creation, all the clone's unmasked properties will be modified, too.
Fiddle here(http://jsfiddle.net/y5b5q/1/) (needs Object.create capable browser).
I think the main point in question - is to understand difference between new and Object.create approaches. Accordingly to this answer and to this video new keyword does next things:
Creates new object.
Links new object to constructor function (prototype).
Makes this variable point to the new object.
Executes constructor function using the new object and implicit perform return this;
Assigns constructor function name to new object's property constructor.
Object.create performs only 1st and 2nd steps!!!
In code example provided in question it isn't big deal, but in next example it is:
var onlineUsers = [];
function SiteMember(name) {
this.name = name;
onlineUsers.push(name);
}
SiteMember.prototype.getName = function() {
return this.name;
}
function Guest(name) {
SiteMember.call(this, name);
}
Guest.prototype = new SiteMember();
var g = new Guest('James');
console.log(onlineUsers);
As side effect result will be:
[ undefined, 'James' ]
because of Guest.prototype = new SiteMember();
But we don't need to execute parent constructor method, we need only make method getName to be available in Guest.
Hence we have to use Object.create.
If replace Guest.prototype = new SiteMember();
to Guest.prototype = Object.create(SiteMember.prototype); result be:
[ 'James' ]
Sometimes you cannot create an object with NEW but are still able to invoke the CREATE method.
For example: if you want to define a Custom Element it must derive from HTMLElement.
proto = new HTMLElement //fail :(
proto = Object.create( HTMLElement.prototype ) //OK :)
document.registerElement( "custom-element", { prototype: proto } )
The advantage is that Object.create is typically slower than new on most browsers
In this jsperf example, in a Chromium, browser new is 30 times as fast as Object.create(obj) although both are pretty fast. This is all pretty strange because new does more things (like invoking a constructor) where Object.create should be just creating a new Object with the passed in object as a prototype (secret link in Crockford-speak)
Perhaps the browsers have not caught up in making Object.create more efficient (perhaps they are basing it on new under the covers ... even in native code)
Summary:
Object.create() is a Javascript function which takes 2 arguments and returns a new object.
The first argument is an object which will be the prototype of the newly created object
The second argument is an object which will be the properties of the newly created object
Example:
const proto = {
talk : () => console.log('hi')
}
const props = {
age: {
writable: true,
configurable: true,
value: 26
}
}
let Person = Object.create(proto, props)
console.log(Person.age);
Person.talk();
Practical applications:
The main advantage of creating an object in this manner is that the prototype can be explicitly defined. When using an object literal, or the new keyword you have no control over this (however, you can overwrite them of course).
If we want to have a prototype The new keyword invokes a constructor function. With Object.create() there is no need for invoking or even declaring a constructor function.
It can Basically be a helpful tool when you want create objects in a very dynamic manner. We can make an object factory function which creates objects with different prototypes depending on the arguments received.
You have to make a custom Object.create() function. One that addresses Crockfords concerns and also calls your init function.
This will work:
var userBPrototype = {
init: function(nameParam) {
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
function UserB(name) {
function F() {};
F.prototype = userBPrototype;
var f = new F;
f.init(name);
return f;
}
var bob = UserB('bob');
bob.sayHello();
Here UserB is like Object.create, but adjusted for our needs.
If you want, you can also call:
var bob = new UserB('bob');
While Douglas Crockford used to be a zealous advocate of Object.create() and he is basically the reason why this construct actually is in javascript, he no longer has this opinion.
He stopped using Object.create, because he stopped using this keyword altogether as it causes too much trouble. For example, if you are not careful it can easily point to the global object, which can have really bad consequences. And he claims that without using this Object.create does not make sense anymore.
You can check this video from 2014 where he talks at Nordic.js:
https://www.youtube.com/watch?v=PSGEjv3Tqo0
new and Object.create serve different purposes. new is intended to create a new instance of an object type. Object.create is intended to simply create a new object and set its prototype. Why is this useful? To implement inheritance without accessing the __proto__ property. An object instance's prototype referred to as [[Prototype]] is an internal property of the virtual machine and is not intended to be directly accessed. The only reason it is actually possible to directly access [[Prototype]] as the __proto__ property is because it has always been a de-facto standard of every major virtual machine's implementation of ECMAScript, and at this point removing it would break a lot of existing code.
In response to the answer above by 7ochem, objects should absolutely never have their prototype set to the result of a new statement, not only because there's no point calling the same prototype constructor multiple times but also because two instances of the same class can end up with different behavior if one's prototype is modified after being created. Both examples are simply bad code as a result of misunderstanding and breaking the intended behavior of the prototype inheritance chain.
Instead of accessing __proto__, an instance's prototype should be written to when an it is created with Object.create or afterward with Object.setPrototypeOf, and read with Object.getPrototypeOf or Object.isPrototypeOf.
Also, as the Mozilla documentation of Object.setPrototypeOf points out, it is a bad idea to modify the prototype of an object after it is created for performance reasons, in addition to the fact that modifying an object's prototype after it is created can cause undefined behavior if a given piece of code that accesses it can be executed before OR after the prototype is modified, unless that code is very careful to check the current prototype or not access any property that differs between the two.
Given
const X = function (v) { this.v = v };
X.prototype.whatAmI = 'X';
X.prototype.getWhatIAm = () => this.whatAmI;
X.prototype.getV = () => this.v;
the following VM pseudo-code is equivalent to the statement const x0 = new X(1);:
const x0 = {};
x0.[[Prototype]] = X.prototype;
X.prototype.constructor.call(x0, 1);
Note although the constructor can return any value, the new statement always ignores its return value and returns a reference to the newly created object.
And the following pseudo-code is equivalent to the statement const x1 = Object.create(X.prototype);:
const x0 = {};
x0.[[Prototype]] = X.prototype;
As you can see, the only difference between the two is that Object.create does not execute the constructor, which can actually return any value but simply returns the new object reference this if not otherwise specified.
Now, if we wanted to create a subclass Y with the following definition:
const Y = function(u) { this.u = u; }
Y.prototype.whatAmI = 'Y';
Y.prototype.getU = () => this.u;
Then we can make it inherit from X like this by writing to __proto__:
Y.prototype.__proto__ = X.prototype;
While the same thing could be accomplished without ever writing to __proto__ with:
Y.prototype = Object.create(X.prototype);
Y.prototype.constructor = Y;
In the latter case, it is necessary to set the constructor property of the prototype so that the correct constructor is called by the new Y statement, otherwise new Y will call the function X. If the programmer does want new Y to call X, it would be more properly done in Y's constructor with X.call(this, u)
new Operator
This is used to create object from a constructor function
The new keywords also executes the constructor function
function Car() {
console.log(this) // this points to myCar
this.name = "Honda";
}
var myCar = new Car()
console.log(myCar) // Car {name: "Honda", constructor: Object}
console.log(myCar.name) // Honda
console.log(myCar instanceof Car) // true
console.log(myCar.constructor) // function Car() {}
console.log(myCar.constructor === Car) // true
console.log(typeof myCar) // object
Object.create
You can also use Object.create to create a new object
But, it does not execute the constructor function
Object.create is used to create an object from another object
const Car = {
name: "Honda"
}
var myCar = Object.create(Car)
console.log(myCar) // Object {}
console.log(myCar.name) // Honda
console.log(myCar instanceof Car) // ERROR
console.log(myCar.constructor) // Anonymous function object
console.log(myCar.constructor === Car) // false
console.log(typeof myCar) // object
I prefer a closure approach.
I still use new.
I don't use Object.create.
I don't use this.
I still use new as I like the declarative nature of it.
Consider this for simple inheritance.
window.Quad = (function() {
function Quad() {
const wheels = 4;
const drivingWheels = 2;
let motorSize = 0;
function setMotorSize(_) {
motorSize = _;
}
function getMotorSize() {
return motorSize;
}
function getWheelCount() {
return wheels;
}
function getDrivingWheelCount() {
return drivingWheels;
}
return Object.freeze({
getWheelCount,
getDrivingWheelCount,
getMotorSize,
setMotorSize
});
}
return Object.freeze(Quad);
})();
window.Car4wd = (function() {
function Car4wd() {
const quad = new Quad();
const spareWheels = 1;
const extraDrivingWheels = 2;
function getSpareWheelCount() {
return spareWheels;
}
function getDrivingWheelCount() {
return quad.getDrivingWheelCount() + extraDrivingWheels;
}
return Object.freeze(Object.assign({}, quad, {
getSpareWheelCount,
getDrivingWheelCount
}));
}
return Object.freeze(Car4wd);
})();
let myQuad = new Quad();
let myCar = new Car4wd();
console.log(myQuad.getWheelCount()); // 4
console.log(myQuad.getDrivingWheelCount()); // 2
console.log(myCar.getWheelCount()); // 4
console.log(myCar.getDrivingWheelCount()); // 4 - The overridden method is called
console.log(myCar.getSpareWheelCount()); // 1
Feedback encouraged.
I have a constructor and I don't know the number of arguments it needs, for instance:
function someCtor(a,b,c){
var that = this;
that.a = a;
that.b = b;
that.c = c;
}
I need to create a function which will return the instance of that constructor with a dynamic amount of arguments:
function makeNew(ctor, arguments){
// this doesn't work, but it shows what I'm trying to achieve
return new ctor.apply(arguments);
}
I want to use the function to pass the dynamic arguments to the constructor like below:
var instanceOfCtor = makeNew(someCtor, [5,6,7]);
How to implement this function?
Note: See the ES2015 compatibility note at the end.
You do it by first creating an object setting its underlying prototype to the object the prototype property on the constructor refers to via Object.create, then calling the constructor via Function#apply:
function makeNew(ctor, arguments){
var obj = Object.create(ctor.prototype);
var rv = ctor.apply(obj, arguments);
return rv && typeof rv === "object" ? rv : obj;
}
Note the bit of fiddling at the end, so we're emulating the new operator correctly: When you call a constructor via new, if it returns a non-null object reference, that ends up being the result of the new expression; if it returns anything else (or nothing), the object created by new is the result. So we emulate that.
Even on pre-ES5 browsers, you can emulate enough of Object.create to do that:
if (!Object.create) {
Object.create = function(proto, props) {
if (typeof props !== "undefined") {
throw new Error("The second argument of Object.create cannot be shimmed.");
}
function ctor() { }
ctor.prototype = proto;
return new ctor;
};
}
ES2015 Compatibility Note
If the constructor you're calling was created via ES2015's class syntax, the above won't work, because you can't call ES2015 class constructors that way. For example:
class Example {
constructor(a, b) {
this.a = a;
this.b = b;
}
}
const e = Object.create(Example.prototype);
Example.apply(e, [1, 2]); // TypeError: Class constructor Example cannot be invoked without 'new' (or similar)
The good news is that will only happen on an ES2015+-compatible JavaScript engine, and only if the constructor was created via class; the bad news is that it can happen.
So how do you make your makeNew bulletproof?
It turns out this is quite easy, because ES2015 also added Reflect.construct, which does exactly what you want makeNew to do but does it in a way that's compatible with both class constructors and function constructors. So you can feature-detect Reflect.construct and use it if it's present (ES2015 JavaScript engine, so a constructor might have been created with class) and fall back to the above if it's not there (pre-ES2015 engine, there won't be any class constructors around):
var makeNew; // `var` because we have to avoid any ES2015+ syntax
if (typeof Reflect === "object" && Reflect && typeof Reflect.construct === "function") {
// This is an ES2015-compatible JavaScript engine, use `Reflect.construct`
makeNew = Reflect.construct;
} else {
makeNew = function makeNew(ctor, arguments){
var obj = Object.create(ctor.prototype);
var rv = ctor.apply(obj, arguments);
return rv && typeof rv === "object" ? rv : obj;
};
}
That's pure ES5 syntax, so runs on ES5 engines, but uses ES2015's Reflect.construct if it's present.
I'm trying to override methods of an object but still call the prototype's original method using Object.getPrototypeOf(). This works great the first time, but if the method is overridden more than once there are problems.
This code results in a stack overflow:
A =
{
blurg: function()
{
puts('hey there')
}
}
B = (function buildB(){
var obj = Object.create(A)
obj.blurg = function()
{
Object.getPrototypeOf(this).blurg.apply(this, arguments)
puts('hai!!!!')
}
return obj
})()
b = (function buildb(){
var obj = Object.create(B)
obj.blurg = function()
{
Object.getPrototypeOf(this).blurg.apply(this, arguments)
puts('bye bye')
}
return obj
})()
b.blurg()
jsFiddle
The problem is that I want to call the prototype's method with the current object as this. This causes problems when that method does the same thing.
Am I going about this the wrong way? Is there a way I could create a helper function for making sure the correct prototype is pulled up? I'm a bit at a loss.
The problem is that in JavaScript, by nature, this always refers to the bottom down object instance in a prototype chain, so when you override methods in a hierarchical structure like above, this.prototype.someMethod() refers to the exact base class of the object instance, it doesn't seem to be a problem when you have maximum of two levels of hierarchy, however when you define three levels of hierarchical structure or more, recursion is inevitable! here's how:
A: grand super class
B: super class - inherits from A (B.prototype = A)
C: class - inherits from B (C.prototype = B)
a: instance of A (defines someMethod)
b: instance of B (defines someMethod, calls A.someMethod through Object.getPrototypeOf(this))
c: instance of C (defines someMethod, calls B.someMethod through Object.getPrototypeOf(this))
When b.someMethod is called, it can successfully call A's someMethod (Object.getPrototypeOf(this) returns A when called by b)
However when c.someMethod is called, it first calls b.someMethod, which in turn calls b.someMethod because Object.getPrototypeOf(this) always returns B when called by c! And here's where stack overflow occurs.
To resolve this, try to store a base class reference whenever you define a new sub-class, avoid using this when calling a super-class method:
A =
{
blurg: function () {
console.log('hey there')
}
};
B = (function buildB() {
var obj = Object.create(A);
var base = Object.getPrototypeOf(obj);
obj.blurg = function () {
base.blurg.apply(this, arguments);
console.log('hai!!!!')
}
return obj
})();
C = (function buildb() {
var obj = Object.create(B);
var base = Object.getPrototypeOf(obj);
obj.blurg = function () {
base.blurg.apply(this, arguments);
console.log('bye bye');
}
return obj
})();
C.blurg();
I admit this question is getting to the limits of what I know of JavaScript & jQuery, and there is probably a more proper way to state my question (which would help in finding an existing solution), but if you can bear with me, this is what I'm after.
I have an existing object class I've defined. I'm making a jQuery ajax call using getJSON, and I want my callback parameter (which is an object) to be classed as my custom object, so that I can access that class' methods from it.
So I have some object class
function Boo() {
this.param1;
this.param2;
this.yah = function() {
...
}
}
and then I have something elsewhere of the sort
$.getJSON(url,function(new_instance) {
//from my php source this passed object is already loaded with param1, param2...
alert(new_instance.param1); //no probs
//but i want to be able to then call
new_instance.yah();
});
In other words, I want new_instance to be considered an instance of Boo(). I know in stuff like ActionScript you have to class the incoming parameters for exactly this reason, dunno what flexibility I have in JS.
I thought maybe about having an intermediate function that takes in the incoming object and creates/populates a new instance of Boo() but not sure if there is a more clever method.
Many thanks!!
Do not define methods in the constructor function, you are
defining them over and over again every time the costructor
is called. Move them over to the prototype:
Boo.prototype = {
yah: function() {
},
bah: function() {
}
...
};
a little helper function:
function coerceTo( proto, values ) {
var r = Object.create( proto );
for( var key in values ) {
r[key] = values[key];
}
return r;
}
Depending on browser, Object.create might not be available, so:
if (!Object.create) {
Object.create = function (o) {
if (arguments.length > 1) {
throw new Error('Object.create implementation only accepts the first parameter.');
}
function F() {}
F.prototype = o;
return new F();
};
}
Usage:
new_instance = coerceTo( Boo.prototype, new_instance );
new_instance instanceof Boo //true
new_instance.yah();
What you can do:
$.getJSON(url,function(newObjData) {
var newObj = $.extend(new Boo(), newObjData);
newObj.yah();
});
Also consider moving your Boo methods to object prototype so the methods don't get recreated for each Boo instance:
var Boo = function() {
this.param1;
this.param2;
}
Boo.prototype.yah = function() {
console.log(this.param1);
}
Scenario 1 - everything works:
var AwesomeObject = function()
{
var self = this;
self.whatstuff = 'really awesome';
}
AwesomeObject.prototype.doStuff = function()
{
var self = this;
console.log('i did '+self.whatstuff+' stuff');
return self;
}
var awesome = new AwesomeObject(); //returns a new AwesomeObject
awesome.doStuff(); // prints 'i did really awesome stuff' on the console
Now i want it even awesomer:
var AwesomeObject = function()
{
var f = function() { console.log('i am awesome'); }
var self = f;
self.whatstuff = 'really awesome';
return self;
}
AwesomeObject.prototype.doStuff = function()
{
var self = this;
console.log('i did '+self.whatstuff+' stuff');
return self;
}
var awesome = new AwesomeObject(); //returns the interal f object
awesome(); // prints 'i am awesome'
awesome.doStuff(); // throws an error
new AwesomeObject should return an executable function itself, so that i can say 'awesome();'
but i want it to inherit the AwesomeObject.prototype, too.
adding self.prototype = AwesomeObject.prototype; does not help.
var AwesomeObject = function()
{
var f = function() { console.log('i am awesome'); }
var self = f;
self.whatstuff = 'really awesome';
self.prototype = AwesomeObject.prototype;
return self;
}
ok i can copy the AwesomeObject.prototype functions - one after the other - into the scope of f
var AwesomeObject = function()
{
var f = function() { console.log('i am awesome'); }
var self = f;
self.whatstuff = 'really awesome';
self.doStuff = function() { AwesomeObject.prototype.doStuff.apply(self,arguments); }
return self;
}
but i think there must be a better way, a better pattern, what is it?
this issue drives me crazy, help would be really appreciated.
in general: how to create a function object that
can be created with new
returns a function object that can be executed
inherits all properties and methods of a given prototype
?
is there a way?
thx
Franz
A very simple pattern is a factory.
var AwesomeObject = (function() {
var AwesomeObject = function() {
this.whatstuff = 'really awesome';
};
AwesomeObject.prototype.doStuff = function() {
console.log('i did ' + this.whatstuff + ' stuff');
return this;
};
return function() {
var o = new AwesomeObject();
var f = function() { console.log("I am awesome"); };
for (var k in o) {
f[k] = o[k];
}
return f;
};
})();
var foo = AwesomeObject();
foo();
foo.doStuff();
Live Example.
The idea is that you seperate your function and your object into two things. Your object exists in the local scope of your function and the function can use the object.
The object itself inherits completely through the prototype.
The key is do forward all properties/methods of the object onto the function.
This is the cleanest solution.
When a property is resolved the prototype chain is traversed as you probably know.
But if you have an object awesome and try to evaluate awesome.doStuff, then awesome.prototype will never be queried for the property. You can verify this in your example, "doStuff" in awesome => false but "doStuff" in awesome.prototype => true.
So what you're doing is not changing the implicit properties of awesome, you are changing its prototype, meaning any objects created by doing new awesome will have that property. Verification: "doStuff" in new awesome() => true. And this makes sense, since there is no way to distinguish between a constructor or a regular function when using f/awesome.
The procedure when resolving a property p on an object o is roughly as follows:
Check whether p is defined on o
Check whether p is defined on o.__proto__ (usage of __proto__ is non-standard but widely implemented, except for jscript last time i checked and it has now been deprecated in SpiderMonkey)
Check whether p is defined on o.constructor.prototype
Check whether p is defined on o.constructor.prototype.prototype
etc
So one solution would be to simply set o.__proto__ = AwesomeClass.prototype. Think of __proto__ as a hidden intermediary object between an object and its prototype. Each instance receives its own unique __proto__ object. But this is deprecated and non-standard like I said.
We could also set the values in Function.prototype but that would override other Function properties and affect all Function instances. We don't want that.
So what's left? Not much it turns out. There is no way to set the complete prototype of an object while retaining it's inherited prototype. You will need to iterate through your prototype and copy all properties. Fortunately this will allow instanceof to behave as expected when working with chains of constructors, as well as allowing inheritance/overriding of properties properly.
The problem is really that there is no built-in way to copy the properties of an object into another one, and that there is no standard way to change an object's prototype chain ad-hoc (__proto__).
So use __proto__, or iterate through the prototype.
I don't think there is a good way to do this. I would redesign your program to avoid it.
However, here is a bad, platform-dependent solution (works on V8 using non-standard __proto__ property):
var PrototypeToBeInherited = {'inheritedProperty': 'inheritedPropertyValue'};
f = function() {
return "result";
};
f.__proto__ = PrototypeToBeInherited;
f()
=> "result";
f.inheritedProperty
=> "inheritedPropertyValue"
For your requirement that it must be created with "new", just wrap it in function:
F = function() {
return f;
}
var instance = new F();