简体   繁体   中英

Rewrite object's constructor's prototype doesn't work

Here is my code:

function Class() {};

Class.prototype.extend = function () {
    var instance = new Class();
    instance.constructor.prototype = {
        say: function () {
            console.log("Hello");
        }
    }
    console.log(instance); //Class {extend: function}
}

Class.extend = function () {
    this.prototype.extend();
}

Class.extend();

In the extend method, I rewrite an instance's prototype instance.constructor.prototype = {..} ,

however, when I log the instance, it doesn't show the say method

Why the rewrite doesn't work? How can I let it work?

Here is the demo

When you assign a new prototype object only newly instantiated objects will have the new prototype:

function Class() {};

Class.prototype.extend = function () {
    var instance = new Class();
    instance.constructor.prototype = {
        say: function () {
            console.log("Hello");
        }
    }
    console.log(instance);    //Class {extend: function}
    console.log(new Class()); //Class {say: function}
}

Class.extend = function () {
    this.prototype.extend();
}

Class.extend();

This is because the reference to the prototype object is copied from the constructor's prototype at the time the object is instantiated. If you want to add to the prototype of all existing instances and future instance you can just modify the prototype object rather than assigning a whole new object to the constructor:

function Class() {};

Class.prototype.extend = function () {
    var instance = new Class();
    instance.constructor.prototype.say = function () {
        console.log("Hello");
    }
    delete instance.constructor.prototype.extend;
    console.log(instance); //Class {say: function}
}

Class.extend = function () {
    this.prototype.extend();
}

Class.extend();

You successfully changed Class.prototype , but you changed it to a totally different object .

instance has a reference to its prototype object, called instance.__proto__ . When a new Class instance is created, the __proto__ of the instance points to the same object as Class.prototype .

However, your change what Class.prototype refers to . This will affect the __proto__ of future instances, but not of any existing instances . instance.__proto__ still points to the old object that Class.prototype used to refer to.

This is how it looks at first, after instance is constructed:

instance.__proto__ ===> { extend: function } <=== Class.prototype

This is how it looks after assignment of Class.prototype to a new object:

instance.__proto__ ===> { extend: function }
                        { say:    function } <=== Class.prototype

Instead , you want to modify the object Class.prototype refers to:

instance.constructor.prototype.say = function () {
    console.log("Hello");
}

That will get you a final picture like this:

instance.__proto__ ===> { extend: function, say: function } <=== Class.prototype

See that Class.prototype and instance.__proto__ still point to the same object, but the object itself now has an additional property.

I does add this function. But you are changing the prototype object itself, rather than changing its properties:

Demo

Class.prototype.extend = function () {
    var instance = new Class();
    instance.constructor.prototype.say =
        function () {
            console.log("Hello");
        }
    console.log(instance);
    // Class {extend: function, say: function}

}

When you're trying to access some_obj.some_field the JS engine itself will first check objects own properties and then will go to some_obj.prototype and look for some_field .

By assigning instance.constructor.prototype = {...} you are changing where prototype will point for all newly created objects, but not for already existing ones.

Though a non-standard approach, this will help you incase the JS environment allows you to edit proto internal property.

function Class() {};

Class.prototype.extend = function () {
    var instance = new Class();
    instance.__proto__ = instance.constructor.prototype = {
        say: function () {
            console.log("Hello");
        }
    }


    console.log(instance); //Class {extend: function}
    console.log(instance.say)
}

Class.extend = function () {
    this.prototype.extend();
}

Class.extend();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM