0

这是我的代码:

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方法

为什么重写不起作用?我怎样才能让它工作?

这是演示

4

4 回答 4

1

你成功地改变了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.prototype并且instance.__proto__仍然指向同一个对象,但是对象本身现在具有附加属性。

于 2013-07-30T16:28:35.887 回答
1

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

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();
于 2013-07-30T16:25:11.290 回答
0

我确实添加了这个功能。但是您正在更改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_fieldJS 引擎本身时,它会首先检查对象自身的属性,然后会去some_obj.prototype查找some_field.

通过分配instance.constructor.prototype = {...},您正在更改prototype所有新创建对象的指向位置,但不是已经存在的对象。

于 2013-07-30T16:16:20.703 回答
0

虽然是一种非标准方法,但这将帮助您在 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();
于 2013-07-30T16:24:37.407 回答