2017-05-03 105 views
7

我創建了2個原型實例,更改了原型中的函數,更改反映在兩個實例中(Great)。 但是,當我通過刪除函數來修改原型時,該函數對於現有實例仍然存在。Javascript:修改原型不會影響現有實例

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是否按預期工作和設置protoype回空後,線4表示預計未定義。然而第3行仍然顯示功能定義。

+6

您並未修改原型對象,而是創建了一個新對象。 – Bergi

+0

另請參見[與'instanceof'相同的混淆](http://stackoverflow.com/q/14568239/1048572)和[如何正確定義Javascript原型](http://stackoverflow.com/q/17474390/ 1048572) – Bergi

+2

您實際上已將原型屬性重新分配給一個新對象。舊的仍然存在。 – abhishekkannojia

回答

5

實質上,您將重新指定函數Aprototype屬性以指向新對象。這不會影響舊對象,因此不會影響先前的實例。

下面是對正在發生的事情的說明。

此代碼後執行:

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

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

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

的情況如下:再經過

before

代碼執行:

A.prototype = {}; 

var a3 = new A(); 

A.prototype點到一個新的對象但是舊實例的屬性仍指向舊對象。

after

如果你想真正去除方法,你必須編輯原始對象,而不是指向一個新的。

要真正原形從howCool()方法,像這樣的工作:

delete A.prototype.howCool 

這將使:

finally

現在,任何未來的實例,例如a3,而先前的那些,都將仍然指向相同的對象,但該對象將不具有howCool()方法。

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

+0

或'A.prototype.howCool = undefined;'。 – GramThanos

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`新的實例。

0

下面是可能的解釋:
(注:下面的解釋是隻爲實驗和概念理解爲__proto__的使用應在生產代碼來避免)

如你所知,有之間的聯繫一個對象(在本例中爲a1)以及創建該對象的構造函數的原型(在本例中爲A)。 此鏈接被稱爲__proto__或dunder proto。所以在這種情況下可以看作a1.__proto__

現在發生的事情是,當你說A.prototype = {};時,此時對象a1已經被構建,並且它通過這個鏈接指向A.prototype。

由於JavaScript是垃圾收集語言,只是將A.prototype設置爲{}並沒有清理舊的protoytpe對象,因此舊對象仍然徘徊不前。 所以當你說console.log(a1.howCool());時,howCool位於滯留物體中。

因此,如果您修改3號線這樣的:

// 3號線

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

你就可以看到舊的原型對象和howCool()裏面在控制檯窗口中的行console.log(a1.__proto__); 但是,如果您設置了a1.__proto__ = {};,則console.log(a1.howCool());將無法​​找到該對象,並且找不到howCool()(因爲它現在設置爲空對象)。

因此,將A.prototype設置爲{}並不會達到與a.__proto__ = {}相同的效果。

因此,你看到的輸出。

希望它有幫助。

+0

請不要使用'__proto__',它已被棄用併產生錯誤的展示。使用標準的'Object.getPrototypeOf'。 – Bergi

+0

@Bergi當然,我不打算使用它。這只是爲了解釋OP看到的行爲背後的原因。我只是不想將他與其他細節混淆。他更容易在控制檯窗口中的a1對象上看到此屬性。 –

+0

除*它不是一個實際的屬性,因此混淆imo。 – Bergi

相關問題