Reputation: 5957
I get a promise object from my DB with Angular.
I want this object return true when I call myObj instanceof CustomObject
, but without modify the promise comportment.
For the moment I wrote:
function CustomObject(myExistingPromise) {
this.obj = myExistingPromise;
};
But to manipulate my promise I need to to (new CustomObject(myExistingPromise)).obj
instead of new CustomObject(myExistingPromise)
Is there a way to do it?
Upvotes: 2
Views: 163
Reputation: 1075059
TL;DR - Use duck typing instead; stick a property on the object or something and use that rather than instanceof CustomObject
. You can do what you want in cutting-edge browsers, or at least get close, but it's really ugly.
The full monty:
instanceof
basically walks through the prototype chain of the object and compares each entry in the chain against the prototype
property of the function you refer to (e.g., obj instanceof CustomObject
searches the prototype chain of obj
looking for CustomObject.prototype
).
So in order to retroactively make instanceof
true, you'd have to insert CustomObject.prototype
into the prototype chain of the object.
You cannot currently do that within the standard; there's no way to set the prototype of an existing object. In ES5, you can get the prototype via getPrototypeOf
, but to set it you need setPrototypeOf
, which will be in ES6 (cutting-edge versions of modern browsers already have it — IE11+, Firefox 31+, Chrome 34+; chart).
But doing it is really ugly and has significant side-effects.
Basically, what you'd do is insert CustomObject.prototype
as the prototype of the promise's base prototype (the one just above Object.prototype
in the chain). This means all objects created by the same constructor as the promise will also magically become instanceof CustomObject
, not just the one we act on. This really does not seem like a good idea, but if you really want to do it, there's an example below.
To affect only the one instance of the object, you can't quite do it, but you can get close. You can give the object a new prototype based on CustomObject.prototype
and copy over all of the properties of its original prototype that you can see (e.g., the enumerable ones). The problems are A) Perhaps that prototype has non-enumerable properties that are important, and B) That would make it no longer instanceof
its original constructor (as the original constructor's prototype is no longer in the chain). (B) may or may not be a problem (most people use duck typing, not instanceof
), but (A) would make the solution fairly fragile.
Bottom-line: I recommend finding a different way, rather than requiring that the object be instanceof CustomObject
. Put a marker property on it or something.
Injecting CustomObject.prototype
into the base of the prototype chain of the object, which will affect all objects created by the original object's constructor: (The key bit is the monkeyPatchConstructorPrototype
function)
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Inserting Prototype</title>
</head>
<body>
<script>
(function() {
"use strict";
// The original constructor
function Original() {
}
// The one we want to insert
function InsertMe() {
}
// Create an object; also another we'll come back to
var obj = new Original();
var obj2 = new Original();
// Check it
display("Before:");
display("obj instanceof Original? " + (obj instanceof Original));
display("obj instanceof InsertMe? " + (obj instanceof InsertMe));
// Insert our prototype into its chain
monkeyPatchConstructorPrototype(obj, InsertMe);
// Check it again
display("After:");
display("obj instanceof Original? " + (obj instanceof Original));
display("obj instanceof InsertMe? " + (obj instanceof InsertMe));
// But note that `obj2` is also affected, because we changed
// the prototype of its prototype:
display("Previously-created objects are also affected:")
display("obj2 instanceof Original? " + (obj2 instanceof Original));
display("obj2 instanceof InsertMe? " + (obj2 instanceof InsertMe));
// And in fact all other objects created by that same prototype,
// even in the future, are also affected:
var obj3 = new Original();
display("As are ones created afterward:")
display("obj3 instanceof Original? " + (obj3 instanceof Original));
display("obj3 instanceof InsertMe? " + (obj3 instanceof InsertMe));
// Insert ctor.prototype into the base of the given object's
// prototype chain. This does not only affect the given object,
// but anything else that shares its prototype unless the object's
// immediate prototype is Object.prototype or null.
function monkeyPatchConstructorPrototype(o, ctor) {
var proto;
// No need if already done
if (o instanceof ctor) {
return;
}
// Find the root prototype of the object, the one whose
// prototype is Object.prototype or null
proto = Object.getPrototypeOf(o);
while (proto !== Object.prototype && proto !== null) {
o = proto;
proto = Object.getPrototypeOf(o);
}
// Give it ctor.prototype
Object.setPrototypeOf(o, ctor.prototype);
}
function display(msg) {
var p = document.createElement('p');
p.innerHTML = String(msg);
document.body.appendChild(p);
}
})();
</script>
</body>
</html>
Live Example (Only works in cutting-edge browsers, see note and chart link above)
Output:
Before: obj instanceof Original? true obj instanceof InsertMe? false After: obj instanceof Original? true obj instanceof InsertMe? true Previously-created objects are also affected: obj2 instanceof Original? true obj2 instanceof InsertMe? true As are ones created afterward: obj3 instanceof Original? true obj3 instanceof InsertMe? true
Upvotes: 2
Reputation:
thats rubbish because you can easily achieve the same i wrote. with
var CustomObject=angular constructor, or
var CustomObject=obj.constructor;
first generate once obj than add this if you dont know the constructor... now you can generate a new CustomObject over the Angular constructor.
function CustomObject (Angularvalue1, Angularvalue2, .....)
{
CustomObject.constructor.call (this,Angularvalue1, Angularvalue2, .....);
}
CustomObject.constructor=obj.constructor; // if you know the constructor of Angluar replace obj.constructor with the angular obj constructor function
CustomObject.prototype=obj.constructor.prototype;
CustomObject.prototype.constructor=CustomObject; //---this line would change also the constructor property of the angular constructor, remove it
var myObject=new CustomObject (Angularvalue1, Angularvalue2, .....)
Upvotes: 1