重写对象的构造函数的原型不起作用



这是我的代码:

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

extend方法中,我重写了一个实例的原型instance.constructor.prototype = {..}

然而,当我记录实例时,它没有显示say方法

为什么重写不起作用?我该如何让它发挥作用?

这是的演示

您成功更改了Class.prototype,但将其更改为完全不同的对象。

instance有一个对其原型对象的引用,称为instance.__proto__。创建新的Class实例时,该实例的__proto__指向与Class.prototype相同的对象。

但是,您的更改Class.prototype指的是。这将影响未来实例的__proto__,但不会影响任何现有实例instance.__proto__仍然指向Class.prototype曾经引用的旧对象

instance构建完成后,它最初的样子是这样的:

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

这就是将Class.prototype分配给新对象后的样子

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

相反,您希望修改Class.prototype引用的对象

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

这会给你一张这样的最后照片:

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

请注意,Class.prototypeinstance.__proto__仍然指向同一个对象,但对象本身现在具有一个附加属性。

当您分配一个新的原型对象时,只有新实例化的对象才会有新的原型:

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

这是因为对原型对象的引用是在实例化对象时从构造函数的原型中复制的。如果你想添加到所有现有实例和未来实例的原型中,你可以修改原型对象,而不是将一个全新的对象分配给构造函数:

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

虽然这是一种非标准的方法,但它将帮助您JS环境允许您编辑proto内部属性。

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

我确实添加了这个函数。但您正在更改prototype对象本身,而不是更改其属性:

演示

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

当您尝试访问some_obj.some_field时,JS引擎本身将首先检查对象自身的属性,然后转到some_obj.prototype并查找some_field

通过指定instance.constructor.prototype = {...},可以更改prototype将指向所有新创建的对象的位置,但不适用于已存在的对象。

最新更新