Javascript:修改Prototype不会影响现有实例

时间:2017-05-03 16:02:28

标签: javascript ecmascript-6 prototype

我创建了2个原型实例,在原型中更改了一个函数,两个实例中都反映了变化(很棒)。 但是,当我通过删除函数修改原型时,该函数仍然存在于现有实例中。

function A() {
  this.name = "cool";
}

A.prototype = {
  howCool: function() {
    return this.name + "er";
  }
};

var a1 = new A(),
  a2 = new A();

a1.name = "hot";
//line1
console.log(a1.howCool());
//line2
console.log(a2.howCool());

A.prototype = {};

//line3
console.log(a1.howCool());

//line4
var a3 = new A();
console.log(a3.howCool());

第1行和第2行按预期工作,在将原型设置为空后,第4行显示未定义的预期值。 但是第3行仍然显示了函数定义。

4 个答案:

答案 0 :(得分:5)

基本上,您重新分配函数prototype的{​​{1}}属性以指向新对象。这不会影响旧对象,因此不会影响先前的实例。

以下是对正在发生的事情的说明。

执行此代码后:

A

情况如下:

before

然后执行此代码:

function A() {
  this.name = "cool";
}

A.prototype = {
  howCool: function() {
    return this.name + "er";
  }
};

var a1 = new A(),
  a2 = new A();

A.prototype = {}; var a3 = new A(); 指向新对象,但旧实例的[[Prototype]]属性仍指向旧对象。

after

如果要实际删除该方法,则必须编辑原始对象,而不是指向新对象。

要从原型中实际删除A.prototype方法,可以使用以下方法:

howCool()

哪会给:

finally

现在任何未来的实例,例如delete A.prototype.howCool 和之前的实例,仍将指向同一个对象,但该对象不会拥有a3方法。

答案 1 :(得分:1)

如果您修改原型,它将影响旧实例,但如果您创建一个新实例,它将不会影响旧实例。

所以当你写:

A.prototype = {};
//line3
console.log(a1.howCool);

对象a1.__proto__仍然指向最初的A.prototype,这就是为什么它不会记录undefined

然后当你写:

//line4
var a3 = new A();
console.log(a3.howCool());

新实例a3正在使用新创建的A.prototype,这就是为什么你得到了'ndefined`。

答案 2 :(得分:0)

尝试使用delete运算符



function A(){
    this.name = "cool";
}

A.prototype = {
    howCool : function(){
        return this.name + "er";
    }
};

var a1 = new A(),
    a2 = new A();

a1.name = "hot";
//line1
console.log(a1.howCool);
//line2
console.log(a2.howCool);

delete A.prototype.howCool;

//line3
console.log(a1.howCool);

//line4
var a3 = new A();
console.log(a3.howCool);




答案 3 :(得分:0)

以下是可能的解释:
(注意:以下说明仅适用于实验和概念性理解,因为在生产代码中应避免使用__proto__)

如您所知,对象(在本例中为a1)与构造函数原型(在本例中为A)之间存在链接,从而创建了对象。 此链接称为__proto__或dunder proto。所以在这种情况下,它可以被视为a1.__proto__

现在,发生的事情就是当你说A.prototype = {};时,此时对象a1已经被构造,它通过这个链接指向A.prototype。

由于Javascript是垃圾收集语言,因此仅将A.prototype设置为{}并不会立即清理旧的protoytpe对象,因此较旧的对象仍然挥之不去。 因此,当您说console.log(a1.howCool());时,howCool位于延迟对象中。

所以,如果你像这样修改你的line3:

// line3中

console.log(a1.__proto__);
a1.__proto__ = {};
console.log(a1.howCool());

您可以在行console.log(a1.__proto__);的控制台窗口中看到旧的原型对象和howCool() 但是,如果设置a1.__proto__ = {};,则console.log(a1.howCool());将无法找到该对象,并且找不到howCool()(因为它现在设置为空对象)。

所以将A.prototype设置为{}并不能达到与a.__proto__ = {}相同的效果。

因此你看到了输出。

希望它有所帮助。