Domanda

I wanted to comment on this old question, but it appears to be locked.

Here is my use case:

  1. An object obj is created with constructor Base. obj instanceof Base returns true.
  2. I want to change the prototype of obj such that it appears as if obj was constructed from Derived. That is, I want
    • obj to get access to the methods of Derived
    • obj instanceof Derived to return true

The reason is that obj is to have a type in the hierarchy that is unknown at the time of its creation and determined by what happens after. I want to be able to move it down the hierarchy.

I believe I can do this with

obj.__proto__ = Derived.prototype;

but __proto__ will be deprecated in the next version of JavaScript. The proxies API, which has changed since the question I linked above was asked, does not seem to support my use case.

Is there an alternative implementation for my use case that exists now or is planned for the future?

The only alternative I can see right now is to use

obj2 = Object.create(Derived.prototype);
obj2.extend(obj);

and never store more than one reference to obj, but that cost is quite an inconvenience.

Here is a fiddle demonstrating the issue.

È stato utile?

Soluzione

I see no possibility to do that. As RobG demonstrated, you can make instanceof returning false by changing harming the class's prototype property.

Seeing that, I thought you could do it with an extra class, you know, like the F from the common Object.create shim:

Object.newChangeable = function create(b) {
    function F(){b.call(this);}
    F.prototype = b.prototype;
    var f = new F();
    f.change = function change(n) {
        F.prototype = n.prototype;
    };
    return f;
}

var obj = Object.newChangeable(Base);
obj instanceof Base; // true

obj.change(Derived);

But no:

obj instanceof Derived; // still false
obj instanceof Base; // still true

because the internal [[Prototype]] of obj still points to the same as Base.prototype. What you can do is making Derived the new Base:

var obj = new Base;
obj instanceof Base; // true

Derived.prototype = Base.prototype;
Base.prototype = {}; // something else

alert(obj instanceof Derived); // true
alert(obj instanceof Base); // false

But I don't think that is what you wanted, manipulating the right side of the expression instead of changing something at obj :-)

Altri suggerimenti

The instanceof operator just checks if a constructor's public prototype property is on an object's [[Prototype]] chain. One way to break the chain is to change the constructor's prototype:

function Base() {}

var base = new Base();

alert( base instanceof Base); // true

Base.prototype = {};

alert( base instanceof Base); // false
alert( base instanceof Object); // true

The second alert is false because the new Base.prototype is not on the [[Prototype]] chain of base any more (the original one still is though). Note that Object.protoyype still is. The above is one reason why the instanceof operator is not seen as being particularly useful.

To do what you are trying to do, you must create the [[Prototype]] chain when the object is constructed because you can't change it later:

Derived.prototype = new Base();

var base = new Derived();

alert(base instanceof Base); // true
alert(base instanceof Derived); // true

Edit

The requirements were:

  1. An object obj is created with constructor Base. obj instanceof Base returns true.

As shown, that isn't necessarily true. If you have a strategy that depends on instanceof returning a particular value then you are placing a (probably unreasonable) constraint on the design with no clear benefit.

2. I want to change the prototype of obj such that it appears as if obj was constructed from Derived. That is, I want

•obj to get access to the methods of Derived

you can do that by making Base.prototype an instance of Derived (as shown) or by copying the properties to Base.prototype.

•obj instanceof Derived to return true

You can do that by making Base.prototype an instance of Derived before creating any instances of Base.

You can't modify the chain after an instance is created. If you drop the instanceof constraint, then you can add the methods of Derived.prototype by simply copying them to Base.prototype. Another way is using call or apply:

Derived.prototype.someMethod.call(base, ...);

but I suspect you are trying to do something that is not possible.

Did you mean this (a little bit confused about the question and I'm still a learner)

function vehicle(name, color)
{
    if(this instanceof arguments.callee)
    {    
        this.name = name;
        this.color = color;
    }
    else return new arguments.callee(arguments);   
}

vehicle.prototype = {
    getName : function()
    {
        alert(this.name);
    } 
}

function Car(name, color, speed)
{
        this.name = name;
        this.color = color;
        this.speed = speed;
}

Car.prototype = vehicle();
var obj = new Car("Ford", "Red", "200mph");

obj.getName(); // alerts `Ford` using vehicle's/parent's method
alert(obj instanceof vehicle); alerts `True` instanceof vehicle's/parent's constructor

A fiddle is here.

An article by John Resig.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top